summaryrefslogtreecommitdiff
path: root/gnu/llvm/tools
diff options
context:
space:
mode:
authorPatrick Wildt <patrick@cvs.openbsd.org>2017-01-24 08:33:19 +0000
committerPatrick Wildt <patrick@cvs.openbsd.org>2017-01-24 08:33:19 +0000
commitc3f092f69d436105a49162679ffd1ed7a74169c2 (patch)
tree4004f50d7cb494460b2e77c792fa1223957802e3 /gnu/llvm/tools
parent58d2a1455eaf2a25cbbbfd698204928abfcc2ab8 (diff)
Import LLVM 4.0.0 rc1 including clang and lld to help the current
development effort on OpenBSD/arm64.
Diffstat (limited to 'gnu/llvm/tools')
-rw-r--r--gnu/llvm/tools/lld/COFF/Strings.cpp7
-rw-r--r--gnu/llvm/tools/lld/COFF/Strings.h2
-rw-r--r--gnu/llvm/tools/llvm-xray/llvm-xray.cc12
-rw-r--r--gnu/llvm/tools/llvm-xray/xray-account.cc140
-rw-r--r--gnu/llvm/tools/llvm-xray/xray-converter.cc275
-rw-r--r--gnu/llvm/tools/llvm-xray/xray-extract.cc268
6 files changed, 336 insertions, 368 deletions
diff --git a/gnu/llvm/tools/lld/COFF/Strings.cpp b/gnu/llvm/tools/lld/COFF/Strings.cpp
index 89b9c5186fd..d0558413f67 100644
--- a/gnu/llvm/tools/lld/COFF/Strings.cpp
+++ b/gnu/llvm/tools/lld/COFF/Strings.cpp
@@ -8,7 +8,6 @@
//===----------------------------------------------------------------------===//
#include "Strings.h"
-#include <mutex>
#if defined(_MSC_VER)
#include <Windows.h>
@@ -20,12 +19,8 @@ using namespace lld;
using namespace lld::coff;
using namespace llvm;
-Optional<std::string> coff::demangleMSVC(StringRef S) {
+Optional<std::string> coff::demangle(StringRef S) {
#if defined(_MSC_VER)
- // UnDecorateSymbolName is not thread-safe, so we need a mutex.
- static std::mutex Mu;
- std::lock_guard<std::mutex> Lock(Mu);
-
char Buf[4096];
if (S.startswith("?"))
if (size_t Len = UnDecorateSymbolName(S.str().c_str(), Buf, sizeof(Buf), 0))
diff --git a/gnu/llvm/tools/lld/COFF/Strings.h b/gnu/llvm/tools/lld/COFF/Strings.h
index 67fc1c773c6..1f85f3e2da5 100644
--- a/gnu/llvm/tools/lld/COFF/Strings.h
+++ b/gnu/llvm/tools/lld/COFF/Strings.h
@@ -16,7 +16,7 @@
namespace lld {
namespace coff {
-llvm::Optional<std::string> demangleMSVC(llvm::StringRef S);
+llvm::Optional<std::string> demangle(llvm::StringRef S);
}
}
diff --git a/gnu/llvm/tools/llvm-xray/llvm-xray.cc b/gnu/llvm/tools/llvm-xray/llvm-xray.cc
index 17cc9f90dd7..ac5faaa408b 100644
--- a/gnu/llvm/tools/llvm-xray/llvm-xray.cc
+++ b/gnu/llvm/tools/llvm-xray/llvm-xray.cc
@@ -18,6 +18,7 @@
//
#include "xray-registry.h"
#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
@@ -29,21 +30,12 @@ int main(int argc, char *argv[]) {
" This program consolidates multiple XRay trace "
"processing tools for convenient access.\n");
for (auto *SC : cl::getRegisteredSubcommands()) {
- if (*SC) {
- // If no subcommand was provided, we need to explicitly check if this is
- // the top-level subcommand.
- if (SC == &*cl::TopLevelSubCommand) {
- cl::PrintHelpMessage(false, true);
- return 0;
- }
+ if (*SC)
if (auto C = dispatch(SC)) {
ExitOnError("llvm-xray: ")(C());
return 0;
}
- }
}
- // If all else fails, we still print the usage message.
cl::PrintHelpMessage(false, true);
- return 0;
}
diff --git a/gnu/llvm/tools/llvm-xray/xray-account.cc b/gnu/llvm/tools/llvm-xray/xray-account.cc
index 7b684aad693..671a5a073ee 100644
--- a/gnu/llvm/tools/llvm-xray/xray-account.cc
+++ b/gnu/llvm/tools/llvm-xray/xray-account.cc
@@ -18,10 +18,10 @@
#include <utility>
#include "xray-account.h"
+#include "xray-extract.h"
#include "xray-registry.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FormatVariadic.h"
-#include "llvm/XRay/InstrumentationMap.h"
#include "llvm/XRay/Trace.h"
using namespace llvm;
@@ -120,6 +120,16 @@ static cl::opt<std::string>
static cl::alias AccountInstrMap2("m", cl::aliasopt(AccountInstrMap),
cl::desc("Alias for -instr_map"),
cl::sub(Account));
+static cl::opt<InstrumentationMapExtractor::InputFormats> InstrMapFormat(
+ "instr-map-format", cl::desc("format of instrumentation map"),
+ cl::values(clEnumValN(InstrumentationMapExtractor::InputFormats::ELF, "elf",
+ "instrumentation map in an ELF header"),
+ clEnumValN(InstrumentationMapExtractor::InputFormats::YAML,
+ "yaml", "instrumentation map in YAML")),
+ cl::sub(Account), cl::init(InstrumentationMapExtractor::InputFormats::ELF));
+static cl::alias InstrMapFormat2("t", cl::aliasopt(InstrMapFormat),
+ cl::desc("Alias for -instr-map-format"),
+ cl::sub(Account));
namespace {
@@ -146,16 +156,13 @@ bool LatencyAccountant::accountRecord(const XRayRecord &Record) {
auto &ThreadStack = PerThreadFunctionStack[Record.TId];
switch (Record.Type) {
- case RecordTypes::ENTER:
- case RecordTypes::ENTER_ARG: {
+ case RecordTypes::ENTER: {
+ // Function Enter
ThreadStack.emplace_back(Record.FuncId, Record.TSC);
break;
}
- case RecordTypes::EXIT:
- case RecordTypes::TAIL_EXIT: {
- if (ThreadStack.empty())
- return false;
-
+ case RecordTypes::EXIT: {
+ // Function Exit
if (ThreadStack.back().first == Record.FuncId) {
const auto &Top = ThreadStack.back();
recordLatency(Top.first, diff(Top.second, Record.TSC));
@@ -410,97 +417,68 @@ void LatencyAccountant::exportStatsAsCSV(raw_ostream &OS,
using namespace llvm::xray;
-namespace llvm {
-template <> struct format_provider<llvm::xray::RecordTypes> {
- static void format(const llvm::xray::RecordTypes &T, raw_ostream &Stream,
- StringRef Style) {
- switch(T) {
- case RecordTypes::ENTER:
- Stream << "enter";
- break;
- case RecordTypes::ENTER_ARG:
- Stream << "enter-arg";
- break;
- case RecordTypes::EXIT:
- Stream << "exit";
- break;
- case RecordTypes::TAIL_EXIT:
- Stream << "tail-exit";
- break;
- }
- }
-};
-} // namespace llvm
-
static CommandRegistration Unused(&Account, []() -> Error {
- InstrumentationMap Map;
- if (!AccountInstrMap.empty()) {
- auto InstrumentationMapOrError = loadInstrumentationMap(AccountInstrMap);
- if (!InstrumentationMapOrError)
- return joinErrors(make_error<StringError>(
- Twine("Cannot open instrumentation map '") +
- AccountInstrMap + "'",
- std::make_error_code(std::errc::invalid_argument)),
- InstrumentationMapOrError.takeError());
- Map = std::move(*InstrumentationMapOrError);
- }
+ int Fd;
+ auto EC = sys::fs::openFileForRead(AccountInput, Fd);
+ if (EC)
+ return make_error<StringError>(
+ Twine("Cannot open file '") + AccountInput + "'", EC);
+
+ Error Err = Error::success();
+ xray::InstrumentationMapExtractor Extractor(AccountInstrMap, InstrMapFormat,
+ Err);
+ if (auto E = handleErrors(
+ std::move(Err), [&](std::unique_ptr<StringError> SE) -> Error {
+ if (SE->convertToErrorCode() == std::errc::no_such_file_or_directory)
+ return Error::success();
+ return Error(std::move(SE));
+ }))
+ return E;
- std::error_code EC;
raw_fd_ostream OS(AccountOutput, EC, sys::fs::OpenFlags::F_Text);
if (EC)
return make_error<StringError>(
Twine("Cannot open file '") + AccountOutput + "' for writing.", EC);
- const auto &FunctionAddresses = Map.getFunctionAddresses();
+ const auto &FunctionAddresses = Extractor.getFunctionAddresses();
symbolize::LLVMSymbolizer::Options Opts(
symbolize::FunctionNameKind::LinkageName, true, true, false, "");
symbolize::LLVMSymbolizer Symbolizer(Opts);
llvm::xray::FuncIdConversionHelper FuncIdHelper(AccountInstrMap, Symbolizer,
FunctionAddresses);
xray::LatencyAccountant FCA(FuncIdHelper, AccountDeduceSiblingCalls);
- auto TraceOrErr = loadTraceFile(AccountInput);
- if (!TraceOrErr)
+ if (auto TraceOrErr = loadTraceFile(AccountInput)) {
+ auto &T = *TraceOrErr;
+ for (const auto &Record : T) {
+ if (FCA.accountRecord(Record))
+ continue;
+ for (const auto &ThreadStack : FCA.getPerThreadFunctionStack()) {
+ errs() << "Thread ID: " << ThreadStack.first << "\n";
+ auto Level = ThreadStack.second.size();
+ for (const auto &Entry : llvm::reverse(ThreadStack.second))
+ errs() << "#" << Level-- << "\t"
+ << FuncIdHelper.SymbolOrNumber(Entry.first) << '\n';
+ }
+ if (!AccountKeepGoing)
+ return make_error<StringError>(
+ Twine("Failed accounting function calls in file '") + AccountInput +
+ "'.",
+ std::make_error_code(std::errc::executable_format_error));
+ }
+ switch (AccountOutputFormat) {
+ case AccountOutputFormats::TEXT:
+ FCA.exportStatsAsText(OS, T.getFileHeader());
+ break;
+ case AccountOutputFormats::CSV:
+ FCA.exportStatsAsCSV(OS, T.getFileHeader());
+ break;
+ }
+ } else {
return joinErrors(
make_error<StringError>(
Twine("Failed loading input file '") + AccountInput + "'",
std::make_error_code(std::errc::executable_format_error)),
TraceOrErr.takeError());
-
- auto &T = *TraceOrErr;
- for (const auto &Record : T) {
- if (FCA.accountRecord(Record))
- continue;
- errs()
- << "Error processing record: "
- << llvm::formatv(
- R"({{type: {0}; cpu: {1}; record-type: {2}; function-id: {3}; tsc: {4}; thread-id: {5}}})",
- Record.RecordType, Record.CPU, Record.Type, Record.FuncId,
- Record.TId)
- << '\n';
- for (const auto &ThreadStack : FCA.getPerThreadFunctionStack()) {
- errs() << "Thread ID: " << ThreadStack.first << "\n";
- if (ThreadStack.second.empty()) {
- errs() << " (empty stack)\n";
- continue;
- }
- auto Level = ThreadStack.second.size();
- for (const auto &Entry : llvm::reverse(ThreadStack.second))
- errs() << " #" << Level-- << "\t"
- << FuncIdHelper.SymbolOrNumber(Entry.first) << '\n';
- }
- if (!AccountKeepGoing)
- return make_error<StringError>(
- Twine("Failed accounting function calls in file '") + AccountInput +
- "'.",
- std::make_error_code(std::errc::executable_format_error));
- }
- switch (AccountOutputFormat) {
- case AccountOutputFormats::TEXT:
- FCA.exportStatsAsText(OS, T.getFileHeader());
- break;
- case AccountOutputFormats::CSV:
- FCA.exportStatsAsCSV(OS, T.getFileHeader());
- break;
}
return Error::success();
diff --git a/gnu/llvm/tools/llvm-xray/xray-converter.cc b/gnu/llvm/tools/llvm-xray/xray-converter.cc
index aa0da55207b..31275e2902f 100644
--- a/gnu/llvm/tools/llvm-xray/xray-converter.cc
+++ b/gnu/llvm/tools/llvm-xray/xray-converter.cc
@@ -12,16 +12,13 @@
//===----------------------------------------------------------------------===//
#include "xray-converter.h"
-#include "trie-node.h"
+#include "xray-extract.h"
#include "xray-registry.h"
#include "llvm/DebugInfo/Symbolize/Symbolize.h"
#include "llvm/Support/EndianStream.h"
#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/FormatVariadic.h"
-#include "llvm/Support/ScopedPrinter.h"
#include "llvm/Support/YAMLTraits.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/XRay/InstrumentationMap.h"
#include "llvm/XRay/Trace.h"
#include "llvm/XRay/YAMLXRayRecord.h"
@@ -34,14 +31,11 @@ static cl::SubCommand Convert("convert", "Trace Format Conversion");
static cl::opt<std::string> ConvertInput(cl::Positional,
cl::desc("<xray log file>"),
cl::Required, cl::sub(Convert));
-enum class ConvertFormats { BINARY, YAML, CHROME_TRACE_EVENT };
+enum class ConvertFormats { BINARY, YAML };
static cl::opt<ConvertFormats> ConvertOutputFormat(
"output-format", cl::desc("output format"),
cl::values(clEnumValN(ConvertFormats::BINARY, "raw", "output in binary"),
- clEnumValN(ConvertFormats::YAML, "yaml", "output in yaml"),
- clEnumValN(ConvertFormats::CHROME_TRACE_EVENT, "trace_event",
- "Output in chrome's trace event format. "
- "May be visualized with the Catapult trace viewer.")),
+ clEnumValN(ConvertFormats::YAML, "yaml", "output in yaml")),
cl::sub(Convert));
static cl::alias ConvertOutputFormat2("f", cl::aliasopt(ConvertOutputFormat),
cl::desc("Alias for -output-format"),
@@ -78,7 +72,18 @@ static cl::opt<bool> ConvertSortInput(
static cl::alias ConvertSortInput2("s", cl::aliasopt(ConvertSortInput),
cl::desc("Alias for -sort"),
cl::sub(Convert));
-
+static cl::opt<InstrumentationMapExtractor::InputFormats> InstrMapFormat(
+ "instr-map-format", cl::desc("format of instrumentation map"),
+ cl::values(clEnumValN(InstrumentationMapExtractor::InputFormats::ELF, "elf",
+ "instrumentation map in an ELF header"),
+ clEnumValN(InstrumentationMapExtractor::InputFormats::YAML,
+ "yaml", "instrumentation map in YAML")),
+ cl::sub(Convert), cl::init(InstrumentationMapExtractor::InputFormats::ELF));
+static cl::alias InstrMapFormat2("t", cl::aliasopt(InstrMapFormat),
+ cl::desc("Alias for -instr-map-format"),
+ cl::sub(Convert));
+
+using llvm::yaml::IO;
using llvm::yaml::Output;
void TraceConverter::exportAsYAML(const Trace &Records, raw_ostream &OS) {
@@ -90,10 +95,10 @@ void TraceConverter::exportAsYAML(const Trace &Records, raw_ostream &OS) {
for (const auto &R : Records) {
Trace.Records.push_back({R.RecordType, R.CPU, R.Type, R.FuncId,
Symbolize ? FuncIdHelper.SymbolOrNumber(R.FuncId)
- : llvm::to_string(R.FuncId),
- R.TSC, R.TId, R.CallArgs});
+ : std::to_string(R.FuncId),
+ R.TSC, R.TId});
}
- Output Out(OS, nullptr, 0);
+ Output Out(OS);
Out << Trace;
}
@@ -123,20 +128,14 @@ void TraceConverter::exportAsRAWv1(const Trace &Records, raw_ostream &OS) {
// format.
for (const auto &R : Records) {
Writer.write(R.RecordType);
- // The on disk naive raw format uses 8 bit CPUs, but the record has 16.
- // There's no choice but truncation.
- Writer.write(static_cast<uint8_t>(R.CPU));
+ Writer.write(R.CPU);
switch (R.Type) {
case RecordTypes::ENTER:
- case RecordTypes::ENTER_ARG:
Writer.write(uint8_t{0});
break;
case RecordTypes::EXIT:
Writer.write(uint8_t{1});
break;
- case RecordTypes::TAIL_EXIT:
- Writer.write(uint8_t{2});
- break;
}
Writer.write(R.FuncId);
Writer.write(R.TSC);
@@ -147,217 +146,30 @@ void TraceConverter::exportAsRAWv1(const Trace &Records, raw_ostream &OS) {
}
}
-namespace {
-
-// A structure that allows building a dictionary of stack ids for the Chrome
-// trace event format.
-struct StackIdData {
- // Each Stack of function calls has a unique ID.
- unsigned id;
-
- // Bookkeeping so that IDs can be maintained uniquely across threads.
- // Traversal keeps sibling pointers to other threads stacks. This is helpful
- // to determine when a thread encounters a new stack and should assign a new
- // unique ID.
- SmallVector<TrieNode<StackIdData> *, 4> siblings;
-};
-
-using StackTrieNode = TrieNode<StackIdData>;
-
-// A helper function to find the sibling nodes for an encountered function in a
-// thread of execution. Relies on the invariant that each time a new node is
-// traversed in a thread, sibling bidirectional pointers are maintained.
-SmallVector<StackTrieNode *, 4>
-findSiblings(StackTrieNode *parent, int32_t FnId, uint32_t TId,
- const DenseMap<uint32_t, SmallVector<StackTrieNode *, 4>>
- &StackRootsByThreadId) {
-
- SmallVector<StackTrieNode *, 4> Siblings{};
-
- if (parent == nullptr) {
- for (auto map_iter : StackRootsByThreadId) {
- // Only look for siblings in other threads.
- if (map_iter.first != TId)
- for (auto node_iter : map_iter.second) {
- if (node_iter->FuncId == FnId)
- Siblings.push_back(node_iter);
- }
- }
- return Siblings;
- }
-
- for (auto *ParentSibling : parent->ExtraData.siblings)
- for (auto node_iter : ParentSibling->Callees)
- if (node_iter->FuncId == FnId)
- Siblings.push_back(node_iter);
-
- return Siblings;
-}
-
-// Given a function being invoked in a thread with id TId, finds and returns the
-// StackTrie representing the function call stack. If no node exists, creates
-// the node. Assigns unique IDs to stacks newly encountered among all threads
-// and keeps sibling links up to when creating new nodes.
-StackTrieNode *findOrCreateStackNode(
- StackTrieNode *Parent, int32_t FuncId, uint32_t TId,
- DenseMap<uint32_t, SmallVector<StackTrieNode *, 4>> &StackRootsByThreadId,
- DenseMap<unsigned, StackTrieNode *> &StacksByStackId, unsigned *id_counter,
- std::forward_list<StackTrieNode> &NodeStore) {
- SmallVector<StackTrieNode *, 4> &ParentCallees =
- Parent == nullptr ? StackRootsByThreadId[TId] : Parent->Callees;
- auto match = find_if(ParentCallees, [FuncId](StackTrieNode *ParentCallee) {
- return FuncId == ParentCallee->FuncId;
- });
- if (match != ParentCallees.end())
- return *match;
-
- SmallVector<StackTrieNode *, 4> siblings =
- findSiblings(Parent, FuncId, TId, StackRootsByThreadId);
- if (siblings.empty()) {
- NodeStore.push_front({FuncId, Parent, {}, {(*id_counter)++, {}}});
- StackTrieNode *CurrentStack = &NodeStore.front();
- StacksByStackId[*id_counter - 1] = CurrentStack;
- ParentCallees.push_back(CurrentStack);
- return CurrentStack;
- }
- unsigned stack_id = siblings[0]->ExtraData.id;
- NodeStore.push_front({FuncId, Parent, {}, {stack_id, std::move(siblings)}});
- StackTrieNode *CurrentStack = &NodeStore.front();
- for (auto *sibling : CurrentStack->ExtraData.siblings)
- sibling->ExtraData.siblings.push_back(CurrentStack);
- ParentCallees.push_back(CurrentStack);
- return CurrentStack;
-}
-
-void writeTraceViewerRecord(raw_ostream &OS, int32_t FuncId, uint32_t TId,
- bool Symbolize,
- const FuncIdConversionHelper &FuncIdHelper,
- double EventTimestampUs,
- const StackTrieNode &StackCursor,
- StringRef FunctionPhenotype) {
- OS << " ";
- OS << llvm::formatv(
- R"({ "name" : "{0}", "ph" : "{1}", "tid" : "{2}", "pid" : "1", )"
- R"("ts" : "{3:f3}", "sf" : "{4}" })",
- (Symbolize ? FuncIdHelper.SymbolOrNumber(FuncId)
- : llvm::to_string(FuncId)),
- FunctionPhenotype, TId, EventTimestampUs, StackCursor.ExtraData.id);
-}
-
-} // namespace
-
-void TraceConverter::exportAsChromeTraceEventFormat(const Trace &Records,
- raw_ostream &OS) {
- const auto &FH = Records.getFileHeader();
- auto CycleFreq = FH.CycleFrequency;
-
- unsigned id_counter = 0;
-
- OS << "{\n \"traceEvents\": [";
- DenseMap<uint32_t, StackTrieNode *> StackCursorByThreadId{};
- DenseMap<uint32_t, SmallVector<StackTrieNode *, 4>> StackRootsByThreadId{};
- DenseMap<unsigned, StackTrieNode *> StacksByStackId{};
- std::forward_list<StackTrieNode> NodeStore{};
- int loop_count = 0;
- for (const auto &R : Records) {
- if (loop_count++ == 0)
- OS << "\n";
- else
- OS << ",\n";
-
- // Chrome trace event format always wants data in micros.
- // CyclesPerMicro = CycleHertz / 10^6
- // TSC / CyclesPerMicro == TSC * 10^6 / CycleHertz == MicroTimestamp
- // Could lose some precision here by converting the TSC to a double to
- // multiply by the period in micros. 52 bit mantissa is a good start though.
- // TODO: Make feature request to Chrome Trace viewer to accept ticks and a
- // frequency or do some more involved calculation to avoid dangers of
- // conversion.
- double EventTimestampUs = double(1000000) / CycleFreq * double(R.TSC);
- StackTrieNode *&StackCursor = StackCursorByThreadId[R.TId];
- switch (R.Type) {
- case RecordTypes::ENTER:
- case RecordTypes::ENTER_ARG:
- StackCursor = findOrCreateStackNode(StackCursor, R.FuncId, R.TId,
- StackRootsByThreadId, StacksByStackId,
- &id_counter, NodeStore);
- // Each record is represented as a json dictionary with function name,
- // type of B for begin or E for end, thread id, process id (faked),
- // timestamp in microseconds, and a stack frame id. The ids are logged
- // in an id dictionary after the events.
- writeTraceViewerRecord(OS, R.FuncId, R.TId, Symbolize, FuncIdHelper,
- EventTimestampUs, *StackCursor, "B");
- break;
- case RecordTypes::EXIT:
- case RecordTypes::TAIL_EXIT:
- // No entries to record end for.
- if (StackCursor == nullptr)
- break;
- // Should we emit an END record anyway or account this condition?
- // (And/Or in loop termination below)
- StackTrieNode *PreviousCursor = nullptr;
- do {
- writeTraceViewerRecord(OS, StackCursor->FuncId, R.TId, Symbolize,
- FuncIdHelper, EventTimestampUs, *StackCursor,
- "E");
- PreviousCursor = StackCursor;
- StackCursor = StackCursor->Parent;
- } while (PreviousCursor->FuncId != R.FuncId && StackCursor != nullptr);
- break;
- }
- }
- OS << "\n ],\n"; // Close the Trace Events array.
- OS << " "
- << "\"displayTimeUnit\": \"ns\",\n";
-
- // The stackFrames dictionary substantially reduces size of the output file by
- // avoiding repeating the entire call stack of function names for each entry.
- OS << R"( "stackFrames": {)";
- int stack_frame_count = 0;
- for (auto map_iter : StacksByStackId) {
- if (stack_frame_count++ == 0)
- OS << "\n";
- else
- OS << ",\n";
- OS << " ";
- OS << llvm::formatv(
- R"("{0}" : { "name" : "{1}")", map_iter.first,
- (Symbolize ? FuncIdHelper.SymbolOrNumber(map_iter.second->FuncId)
- : llvm::to_string(map_iter.second->FuncId)));
- if (map_iter.second->Parent != nullptr)
- OS << llvm::formatv(R"(, "parent": "{0}")",
- map_iter.second->Parent->ExtraData.id);
- OS << " }";
- }
- OS << "\n }\n"; // Close the stack frames map.
- OS << "}\n"; // Close the JSON entry.
-}
-
namespace llvm {
namespace xray {
static CommandRegistration Unused(&Convert, []() -> Error {
// FIXME: Support conversion to BINARY when upgrading XRay trace versions.
- InstrumentationMap Map;
- if (!ConvertInstrMap.empty()) {
- auto InstrumentationMapOrError = loadInstrumentationMap(ConvertInstrMap);
- if (!InstrumentationMapOrError)
- return joinErrors(make_error<StringError>(
- Twine("Cannot open instrumentation map '") +
- ConvertInstrMap + "'",
- std::make_error_code(std::errc::invalid_argument)),
- InstrumentationMapOrError.takeError());
- Map = std::move(*InstrumentationMapOrError);
- }
+ int Fd;
+ auto EC = sys::fs::openFileForRead(ConvertInput, Fd);
+ if (EC)
+ return make_error<StringError>(
+ Twine("Cannot open file '") + ConvertInput + "'", EC);
- const auto &FunctionAddresses = Map.getFunctionAddresses();
+ Error Err = Error::success();
+ xray::InstrumentationMapExtractor Extractor(ConvertInstrMap, InstrMapFormat,
+ Err);
+ handleAllErrors(std::move(Err),
+ [&](const ErrorInfoBase &E) { E.log(errs()); });
+
+ const auto &FunctionAddresses = Extractor.getFunctionAddresses();
symbolize::LLVMSymbolizer::Options Opts(
symbolize::FunctionNameKind::LinkageName, true, true, false, "");
symbolize::LLVMSymbolizer Symbolizer(Opts);
llvm::xray::FuncIdConversionHelper FuncIdHelper(ConvertInstrMap, Symbolizer,
FunctionAddresses);
llvm::xray::TraceConverter TC(FuncIdHelper, ConvertSymbolize);
- std::error_code EC;
raw_fd_ostream OS(ConvertOutput, EC,
ConvertOutputFormat == ConvertFormats::BINARY
? sys::fs::OpenFlags::F_None
@@ -366,25 +178,22 @@ static CommandRegistration Unused(&Convert, []() -> Error {
return make_error<StringError>(
Twine("Cannot open file '") + ConvertOutput + "' for writing.", EC);
- auto TraceOrErr = loadTraceFile(ConvertInput, ConvertSortInput);
- if (!TraceOrErr)
+ if (auto TraceOrErr = loadTraceFile(ConvertInput, ConvertSortInput)) {
+ auto &T = *TraceOrErr;
+ switch (ConvertOutputFormat) {
+ case ConvertFormats::YAML:
+ TC.exportAsYAML(T, OS);
+ break;
+ case ConvertFormats::BINARY:
+ TC.exportAsRAWv1(T, OS);
+ break;
+ }
+ } else {
return joinErrors(
make_error<StringError>(
Twine("Failed loading input file '") + ConvertInput + "'.",
std::make_error_code(std::errc::executable_format_error)),
TraceOrErr.takeError());
-
- auto &T = *TraceOrErr;
- switch (ConvertOutputFormat) {
- case ConvertFormats::YAML:
- TC.exportAsYAML(T, OS);
- break;
- case ConvertFormats::BINARY:
- TC.exportAsRAWv1(T, OS);
- break;
- case ConvertFormats::CHROME_TRACE_EVENT:
- TC.exportAsChromeTraceEventFormat(T, OS);
- break;
}
return Error::success();
});
diff --git a/gnu/llvm/tools/llvm-xray/xray-extract.cc b/gnu/llvm/tools/llvm-xray/xray-extract.cc
index cd87798d0e6..49ecd742113 100644
--- a/gnu/llvm/tools/llvm-xray/xray-extract.cc
+++ b/gnu/llvm/tools/llvm-xray/xray-extract.cc
@@ -13,16 +13,23 @@
//
//===----------------------------------------------------------------------===//
+#include <type_traits>
+#include <utility>
+
+#include "xray-extract.h"
-#include "func-id-helper.h"
#include "xray-registry.h"
+#include "xray-sleds.h"
+#include "llvm/Object/ELF.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/DataExtractor.h"
+#include "llvm/Support/ELF.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Format.h"
+#include "llvm/Support/YAMLTraits.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/XRay/InstrumentationMap.h"
using namespace llvm;
using namespace llvm::xray;
@@ -41,57 +48,244 @@ static cl::opt<std::string>
static cl::alias ExtractOutput2("o", cl::aliasopt(ExtractOutput),
cl::desc("Alias for -output"),
cl::sub(Extract));
-static cl::opt<bool> ExtractSymbolize("symbolize", cl::value_desc("symbolize"),
- cl::init(false),
- cl::desc("symbolize functions"),
- cl::sub(Extract));
-static cl::alias ExtractSymbolize2("s", cl::aliasopt(ExtractSymbolize),
- cl::desc("alias for -symbolize"),
- cl::sub(Extract));
+
+struct YAMLXRaySledEntry {
+ int32_t FuncId;
+ Hex64 Address;
+ Hex64 Function;
+ SledEntry::FunctionKinds Kind;
+ bool AlwaysInstrument;
+};
+
+namespace llvm {
+namespace yaml {
+
+template <> struct ScalarEnumerationTraits<SledEntry::FunctionKinds> {
+ static void enumeration(IO &IO, SledEntry::FunctionKinds &Kind) {
+ IO.enumCase(Kind, "function-enter", SledEntry::FunctionKinds::ENTRY);
+ IO.enumCase(Kind, "function-exit", SledEntry::FunctionKinds::EXIT);
+ IO.enumCase(Kind, "tail-exit", SledEntry::FunctionKinds::TAIL);
+ }
+};
+
+template <> struct MappingTraits<YAMLXRaySledEntry> {
+ static void mapping(IO &IO, YAMLXRaySledEntry &Entry) {
+ IO.mapRequired("id", Entry.FuncId);
+ IO.mapRequired("address", Entry.Address);
+ IO.mapRequired("function", Entry.Function);
+ IO.mapRequired("kind", Entry.Kind);
+ IO.mapRequired("always-instrument", Entry.AlwaysInstrument);
+ }
+
+ static constexpr bool flow = true;
+};
+}
+}
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(YAMLXRaySledEntry)
namespace {
-void exportAsYAML(const InstrumentationMap &Map, raw_ostream &OS,
- FuncIdConversionHelper &FH) {
+llvm::Error LoadBinaryInstrELF(
+ StringRef Filename, std::deque<SledEntry> &OutputSleds,
+ InstrumentationMapExtractor::FunctionAddressMap &InstrMap,
+ InstrumentationMapExtractor::FunctionAddressReverseMap &FunctionIds) {
+ auto ObjectFile = object::ObjectFile::createObjectFile(Filename);
+
+ if (!ObjectFile)
+ return ObjectFile.takeError();
+
+ // FIXME: Maybe support other ELF formats. For now, 64-bit Little Endian only.
+ if (!ObjectFile->getBinary()->isELF())
+ return make_error<StringError>(
+ "File format not supported (only does ELF).",
+ std::make_error_code(std::errc::not_supported));
+ if (ObjectFile->getBinary()->getArch() != Triple::x86_64)
+ return make_error<StringError>(
+ "File format not supported (only does ELF little endian 64-bit).",
+ std::make_error_code(std::errc::not_supported));
+
+ // Find the section named "xray_instr_map".
+ StringRef Contents = "";
+ const auto &Sections = ObjectFile->getBinary()->sections();
+ auto I = find_if(Sections, [&](object::SectionRef Section) {
+ StringRef Name = "";
+ if (Section.getName(Name))
+ return false;
+ return Name == "xray_instr_map";
+ });
+ if (I == Sections.end())
+ return make_error<StringError>(
+ "Failed to find XRay instrumentation map.",
+ std::make_error_code(std::errc::not_supported));
+ if (I->getContents(Contents))
+ return make_error<StringError>(
+ "Failed to get contents of 'xray_instr_map' section.",
+ std::make_error_code(std::errc::executable_format_error));
+
+ // Copy the instrumentation map data into the Sleds data structure.
+ auto C = Contents.bytes_begin();
+ static constexpr size_t ELF64SledEntrySize = 32;
+
+ if ((C - Contents.bytes_end()) % ELF64SledEntrySize != 0)
+ return make_error<StringError>(
+ "Instrumentation map entries not evenly divisible by size of an XRay "
+ "sled entry in ELF64.",
+ std::make_error_code(std::errc::executable_format_error));
+
+ int32_t FuncId = 1;
+ uint64_t CurFn = 0;
+ std::deque<SledEntry> Sleds;
+ for (; C != Contents.bytes_end(); C += ELF64SledEntrySize) {
+ DataExtractor Extractor(
+ StringRef(reinterpret_cast<const char *>(C), ELF64SledEntrySize), true,
+ 8);
+ Sleds.push_back({});
+ auto &Entry = Sleds.back();
+ uint32_t OffsetPtr = 0;
+ Entry.Address = Extractor.getU64(&OffsetPtr);
+ Entry.Function = Extractor.getU64(&OffsetPtr);
+ auto Kind = Extractor.getU8(&OffsetPtr);
+ switch (Kind) {
+ case 0: // ENTRY
+ Entry.Kind = SledEntry::FunctionKinds::ENTRY;
+ break;
+ case 1: // EXIT
+ Entry.Kind = SledEntry::FunctionKinds::EXIT;
+ break;
+ case 2: // TAIL
+ Entry.Kind = SledEntry::FunctionKinds::TAIL;
+ break;
+ default:
+ return make_error<StringError>(
+ Twine("Encountered unknown sled type ") + "'" + Twine(int32_t{Kind}) +
+ "'.",
+ std::make_error_code(std::errc::executable_format_error));
+ }
+ Entry.AlwaysInstrument = Extractor.getU8(&OffsetPtr) != 0;
+
+ // We replicate the function id generation scheme implemented in the runtime
+ // here. Ideally we should be able to break it out, or output this map from
+ // the runtime, but that's a design point we can discuss later on. For now,
+ // we replicate the logic and move on.
+ if (CurFn == 0) {
+ CurFn = Entry.Function;
+ InstrMap[FuncId] = Entry.Function;
+ FunctionIds[Entry.Function] = FuncId;
+ }
+ if (Entry.Function != CurFn) {
+ ++FuncId;
+ CurFn = Entry.Function;
+ InstrMap[FuncId] = Entry.Function;
+ FunctionIds[Entry.Function] = FuncId;
+ }
+ }
+ OutputSleds = std::move(Sleds);
+ return llvm::Error::success();
+}
+
+Error LoadYAMLInstrMap(
+ StringRef Filename, std::deque<SledEntry> &Sleds,
+ InstrumentationMapExtractor::FunctionAddressMap &InstrMap,
+ InstrumentationMapExtractor::FunctionAddressReverseMap &FunctionIds) {
+ int Fd;
+ if (auto EC = sys::fs::openFileForRead(Filename, Fd))
+ return make_error<StringError>(
+ Twine("Failed opening file '") + Filename + "' for reading.", EC);
+
+ uint64_t FileSize;
+ if (auto EC = sys::fs::file_size(Filename, FileSize))
+ return make_error<StringError>(
+ Twine("Failed getting size of file '") + Filename + "'.", EC);
+
+ std::error_code EC;
+ sys::fs::mapped_file_region MappedFile(
+ Fd, sys::fs::mapped_file_region::mapmode::readonly, FileSize, 0, EC);
+ if (EC)
+ return make_error<StringError>(
+ Twine("Failed memory-mapping file '") + Filename + "'.", EC);
+
+ std::vector<YAMLXRaySledEntry> YAMLSleds;
+ Input In(StringRef(MappedFile.data(), MappedFile.size()));
+ In >> YAMLSleds;
+ if (In.error())
+ return make_error<StringError>(
+ Twine("Failed loading YAML document from '") + Filename + "'.",
+ In.error());
+
+ for (const auto &Y : YAMLSleds) {
+ InstrMap[Y.FuncId] = Y.Function;
+ FunctionIds[Y.Function] = Y.FuncId;
+ Sleds.push_back(
+ SledEntry{Y.Address, Y.Function, Y.Kind, Y.AlwaysInstrument});
+ }
+ return Error::success();
+}
+
+} // namespace
+
+InstrumentationMapExtractor::InstrumentationMapExtractor(std::string Filename,
+ InputFormats Format,
+ Error &EC) {
+ ErrorAsOutParameter ErrAsOutputParam(&EC);
+ if (Filename.empty()) {
+ EC = Error::success();
+ return;
+ }
+ switch (Format) {
+ case InputFormats::ELF: {
+ EC = handleErrors(
+ LoadBinaryInstrELF(Filename, Sleds, FunctionAddresses, FunctionIds),
+ [&](std::unique_ptr<ErrorInfoBase> E) {
+ return joinErrors(
+ make_error<StringError>(
+ Twine("Cannot extract instrumentation map from '") +
+ Filename + "'.",
+ std::make_error_code(std::errc::executable_format_error)),
+ std::move(E));
+ });
+ break;
+ }
+ case InputFormats::YAML: {
+ EC = handleErrors(
+ LoadYAMLInstrMap(Filename, Sleds, FunctionAddresses, FunctionIds),
+ [&](std::unique_ptr<ErrorInfoBase> E) {
+ return joinErrors(
+ make_error<StringError>(
+ Twine("Cannot load YAML instrumentation map from '") +
+ Filename + "'.",
+ std::make_error_code(std::errc::executable_format_error)),
+ std::move(E));
+ });
+ break;
+ }
+ }
+}
+
+void InstrumentationMapExtractor::exportAsYAML(raw_ostream &OS) {
// First we translate the sleds into the YAMLXRaySledEntry objects in a deque.
std::vector<YAMLXRaySledEntry> YAMLSleds;
- auto Sleds = Map.sleds();
- YAMLSleds.reserve(std::distance(Sleds.begin(), Sleds.end()));
+ YAMLSleds.reserve(Sleds.size());
for (const auto &Sled : Sleds) {
- auto FuncId = Map.getFunctionId(Sled.Function);
- if (!FuncId)
- return;
- YAMLSleds.push_back({*FuncId, Sled.Address, Sled.Function, Sled.Kind,
- Sled.AlwaysInstrument,
- ExtractSymbolize ? FH.SymbolOrNumber(*FuncId) : ""});
+ YAMLSleds.push_back({FunctionIds[Sled.Function], Sled.Address,
+ Sled.Function, Sled.Kind, Sled.AlwaysInstrument});
}
- Output Out(OS, nullptr, 0);
+ Output Out(OS);
Out << YAMLSleds;
}
-} // namespace
-
static CommandRegistration Unused(&Extract, []() -> Error {
- auto InstrumentationMapOrError = loadInstrumentationMap(ExtractInput);
- if (!InstrumentationMapOrError)
- return joinErrors(make_error<StringError>(
- Twine("Cannot extract instrumentation map from '") +
- ExtractInput + "'.",
- std::make_error_code(std::errc::invalid_argument)),
- InstrumentationMapOrError.takeError());
+ Error Err = Error::success();
+ xray::InstrumentationMapExtractor Extractor(
+ ExtractInput, InstrumentationMapExtractor::InputFormats::ELF, Err);
+ if (Err)
+ return Err;
std::error_code EC;
raw_fd_ostream OS(ExtractOutput, EC, sys::fs::OpenFlags::F_Text);
if (EC)
return make_error<StringError>(
Twine("Cannot open file '") + ExtractOutput + "' for writing.", EC);
- const auto &FunctionAddresses =
- InstrumentationMapOrError->getFunctionAddresses();
- symbolize::LLVMSymbolizer::Options Opts(
- symbolize::FunctionNameKind::LinkageName, true, true, false, "");
- symbolize::LLVMSymbolizer Symbolizer(Opts);
- llvm::xray::FuncIdConversionHelper FuncIdHelper(ExtractInput, Symbolizer,
- FunctionAddresses);
- exportAsYAML(*InstrumentationMapOrError, OS, FuncIdHelper);
+ Extractor.exportAsYAML(OS);
return Error::success();
});