[compiler-rt] [llvm] [XRay] Draft: Runtime symbol resolution (PR #132416)
Sebastian Kreutzer via llvm-commits
llvm-commits at lists.llvm.org
Fri Mar 21 09:22:29 PDT 2025
https://github.com/sebastiankreutzer created https://github.com/llvm/llvm-project/pull/132416
This is a draft for introducing runtime symbol resolution to XRay and extending the trace file format for the `xray-basic` mode.
This consists of the following changes:
- Adds functionality to resolve function IDs at runtime and exposes it to custom event handlers via `__xray_symbolize`
- Adds a `FunctionRecordBuffer` that stores information for each recorded function ID during tracing
- Increments the basic logging file format version and adds a `FunctionRecordMD` record type that stores function information in the file
- Extends the `llvm-xray` tool to resolve function IDs based on the embedded function records
>From 3ed52428c8c00dd1274a8ddfda00fc2db2b4ae80 Mon Sep 17 00:00:00 2001
From: Sebastian Kreutzer <SebastianKreutzer at gmx.net>
Date: Wed, 6 Nov 2024 11:18:50 +0100
Subject: [PATCH 1/5] [WIP] XRay DSO function resolution
---
compiler-rt/include/xray/xray_interface.h | 20 ++++
compiler-rt/include/xray/xray_records.h | 10 ++
.../sanitizer_symbolizer_libcdep.cpp | 5 +
compiler-rt/lib/xray/CMakeLists.txt | 6 +-
compiler-rt/lib/xray/xray_basic_logging.cpp | 41 +++++++
compiler-rt/lib/xray/xray_interface.cpp | 100 ++++++++++++++++++
.../lib/xray/xray_interface_internal.h | 6 ++
.../TestCases/Posix/export-function-map.cpp | 57 ++++++++++
8 files changed, 243 insertions(+), 2 deletions(-)
create mode 100644 compiler-rt/test/xray/TestCases/Posix/export-function-map.cpp
diff --git a/compiler-rt/include/xray/xray_interface.h b/compiler-rt/include/xray/xray_interface.h
index 675ea0cbc48c8..277b792bdd8b6 100644
--- a/compiler-rt/include/xray/xray_interface.h
+++ b/compiler-rt/include/xray/xray_interface.h
@@ -19,6 +19,26 @@
extern "C" {
+// TODO: The following is for a prototype implementation
+struct FunctionMapEntry {
+ int32_t FunctionId;
+ uint64_t Addr;
+ FunctionMapEntry* Next;
+};
+
+struct XRaySymbolInfo {
+ int32_t FuncId;
+ const char* Name;
+ const char* Module;
+ const char* File;
+ int64_t Line;
+};
+
+extern int __xray_symbolize(int32_t PackedId, XRaySymbolInfo* SymInfo);
+
+extern FunctionMapEntry* __xray_export_function_map();
+
+
/// Synchronize this with AsmPrinter::SledKind in LLVM.
enum XRayEntryType {
ENTRY = 0,
diff --git a/compiler-rt/include/xray/xray_records.h b/compiler-rt/include/xray/xray_records.h
index 89ccb4df2bde6..8b82b6fb79cbc 100644
--- a/compiler-rt/include/xray/xray_records.h
+++ b/compiler-rt/include/xray/xray_records.h
@@ -47,6 +47,7 @@ struct alignas(32) XRayFileHeader {
// reading the data in the file.
bool ConstantTSC : 1;
bool NonstopTSC : 1;
+ bool HasFunctionMap : 1;
// The frequency by which TSC increases per-second.
alignas(8) uint64_t CycleFrequency = 0;
@@ -67,8 +68,17 @@ static_assert(sizeof(XRayFileHeader) == 32, "XRayFileHeader != 32 bytes");
enum RecordTypes {
NORMAL = 0,
ARG_PAYLOAD = 1,
+ FUNC_INFO = 2
};
+struct alignas(16) XRayFunctionInfoRecord {
+ uint16_t RecordType = RecordTypes::FUNC_INFO;
+ int32_t FuncId = 0;
+ int16_t NameLen = 0;
+ int16_t DemangledNameLen = 0;
+ char Padding[6] = {};
+} __attribute__((packed));
+
struct alignas(32) XRayRecord {
// This is the type of the record being written. We use 16 bits to allow us to
// treat this as a discriminant, and so that the first 4 bytes get packed
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cpp
index 74458028ae8f5..d4cfcb5690d3d 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cpp
@@ -435,6 +435,8 @@ bool LLVMSymbolizer::SymbolizeData(uptr addr, DataInfo *info) {
"DATA", info->module, info->module_offset, info->module_arch);
if (!buf)
return false;
+ // FIXME: Remove debug output
+ Report("Response: %s\n", buf);
ParseSymbolizeDataOutput(buf, info);
info->start += (addr - info->module_offset); // Add the base address.
return true;
@@ -469,6 +471,9 @@ const char *LLVMSymbolizer::FormatAndSendCommand(const char *command_prefix,
return nullptr;
}
+ // FIXME: Remove
+ Report("Command: %s\n", buffer_);
+
return symbolizer_process_->SendCommand(buffer_);
}
diff --git a/compiler-rt/lib/xray/CMakeLists.txt b/compiler-rt/lib/xray/CMakeLists.txt
index e7f01a2f4f164..ea9e10978e3e9 100644
--- a/compiler-rt/lib/xray/CMakeLists.txt
+++ b/compiler-rt/lib/xray/CMakeLists.txt
@@ -201,7 +201,8 @@ append_rtti_flag(OFF XRAY_CFLAGS)
set(XRAY_LINK_FLAGS ${COMPILER_RT_COMMON_LINK_FLAGS})
set(XRAY_LINK_LIBS
${COMPILER_RT_UNWINDER_LINK_LIBS}
- ${COMPILER_RT_CXX_LINK_LIBS})
+ ${COMPILER_RT_CXX_LINK_LIBS}
+)
append_list_if(
COMPILER_RT_HAS_XRAY_COMPILER_FLAG XRAY_SUPPORTED=1 XRAY_COMMON_DEFINITIONS)
@@ -212,7 +213,8 @@ add_compiler_rt_component(xray)
set(XRAY_COMMON_RUNTIME_OBJECT_LIBS
RTSanitizerCommon
- RTSanitizerCommonLibc)
+ RTSanitizerCommonLibc
+ RTSanitizerCommonSymbolizer)
# XRay uses C++ standard library headers.
if (TARGET cxx-headers OR HAVE_LIBCXX)
diff --git a/compiler-rt/lib/xray/xray_basic_logging.cpp b/compiler-rt/lib/xray/xray_basic_logging.cpp
index 6ac5417bef754..1be59a277a402 100644
--- a/compiler-rt/lib/xray/xray_basic_logging.cpp
+++ b/compiler-rt/lib/xray/xray_basic_logging.cpp
@@ -27,6 +27,8 @@
#include "sanitizer_common/sanitizer_allocator_internal.h"
#include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_dense_map.h"
+#include "sanitizer_common/sanitizer_symbolizer.h"
#include "xray/xray_records.h"
#include "xray_recursion_guard.h"
#include "xray_basic_flags.h"
@@ -42,6 +44,8 @@ namespace __xray {
static SpinMutex LogMutex;
namespace {
+
+
// We use elements of this type to record the entry TSC of every function ID we
// see as we're tracing a particular thread's execution.
struct alignas(16) StackEntry {
@@ -84,6 +88,8 @@ static atomic_uint64_t ThresholdTicks{0};
static atomic_uint64_t TicksPerSec{0};
static atomic_uint64_t CycleFrequency{NanosecondsPerSecond};
+
+
static LogWriter *getLog() XRAY_NEVER_INSTRUMENT {
LogWriter* LW = LogWriter::Open();
if (LW == nullptr)
@@ -154,6 +160,40 @@ static ThreadLocalData &getThreadLocalData() XRAY_NEVER_INSTRUMENT {
return TLD;
}
+struct FunctionRecordLogger {
+ DenseMap<int32_t, DataInfo> SymInfo;
+
+ static FunctionRecordLogger& Get() {
+ static FunctionRecordLogger Instance;
+ return Instance;
+ }
+
+ static void LogFunctionRecord(int32_t FuncId) {
+ auto& Instance = Get();
+ if (Instance.SymInfo.contains(FuncId)) {
+ return;
+ }
+
+ auto& Entry = Instance.SymInfo[FuncId];
+ Symbolize(FuncId, &Entry);
+ // TODO: handle error
+
+ }
+
+ static void Flush(LogWriter* Writer) {
+ auto& Instance = Get();
+ Instance.SymInfo.forEach([&](auto& Entry) {
+ XRayFunctionInfoRecord FIR;
+ auto& Id = Entry.getFirst();
+ DataInfo& DI = Entry.getSecond();
+ FIR.FuncId = Id;
+ FIR.NameLen = internal_strlen(DI.name);
+ FIR.DemangledNameLen = internal_strlen(DI.name);
+ });
+ Writer->WriteAll();
+ }
+};
+
template <class RDTSC>
void InMemoryRawLog(int32_t FuncId, XRayEntryType Type,
RDTSC ReadTSC) XRAY_NEVER_INSTRUMENT {
@@ -230,6 +270,7 @@ void InMemoryRawLog(int32_t FuncId, XRayEntryType Type,
break;
}
+
// First determine whether the delta between the function's enter record and
// the exit record is higher than the threshold.
XRayRecord R;
diff --git a/compiler-rt/lib/xray/xray_interface.cpp b/compiler-rt/lib/xray/xray_interface.cpp
index 4ec492c266d80..c2d34185290cd 100644
--- a/compiler-rt/lib/xray/xray_interface.cpp
+++ b/compiler-rt/lib/xray/xray_interface.cpp
@@ -31,6 +31,10 @@
#include "sanitizer_common/sanitizer_addrhashmap.h"
#include "sanitizer_common/sanitizer_common.h"
+// TODO: For function map
+#include "sanitizer_common/sanitizer_symbolizer.h"
+
+
#include "xray_defs.h"
#include "xray_flags.h"
@@ -504,6 +508,31 @@ XRayPatchingStatus mprotectAndPatchFunction(int32_t FuncId, int32_t ObjId,
} // namespace
+bool Symbolize(int32_t PackedId, DataInfo* DI) {
+ auto Ids = UnpackId(PackedId);
+ auto ObjId = Ids.first;
+ auto FuncId = Ids.second;
+ auto& SledMap = XRayInstrMaps[ObjId];
+
+ // TODO: Thread safety
+
+ const XRaySledEntry *Sled =
+ SledMap.SledsIndex ? SledMap.SledsIndex[FuncId - 1].fromPCRelative()
+ : findFunctionSleds(FuncId, SledMap).Begin;
+ auto Addr = Sled->function();
+
+ Symbolizer* Sym = Symbolizer::GetOrInit();
+ Sym->RefreshModules(); // FIXME: When is this needed?
+
+ auto Status = Sym->SymbolizeData(Addr, DI);
+
+ printf("Adding Entry: %d -> %x\n", PackedId, Addr);
+ printf("Symbol Info: function %s from module %s in %s:%s\n", DI.name, DI.module, DI.file, DI.line);
+
+ return Status;
+}
+
+
} // namespace __xray
using namespace __xray;
@@ -565,6 +594,77 @@ uint16_t __xray_register_event_type(
return h->type_id;
}
+FunctionMapEntry* __xray_export_function_map() {
+ if (!atomic_load(&XRayInitialized, memory_order_acquire))
+ return {};
+
+ SpinMutexLock Guard(&XRayInstrMapMutex);
+
+ // No atomic load necessary since we have acquired the mutex
+ uint32_t NumObjects = atomic_load(&XRayNumObjects, memory_order_acquire);
+
+ FunctionMapEntry* FMap = new FunctionMapEntry;
+ FMap->Next = nullptr;
+
+ Symbolizer* Sym = Symbolizer::GetOrInit();
+ Sym->RefreshModules();
+
+
+ printf("Objects: %d\n", NumObjects);
+
+
+ FunctionMapEntry* LastEntry = FMap;
+ for (int Obj = 0; Obj < NumObjects; Obj++) {
+ auto& SledMap = XRayInstrMaps[Obj];
+ printf("Functions (%d): %d\n", Obj, SledMap.Functions);
+ for (int F = 1; F <= SledMap.Functions; F++) {
+ const XRaySledEntry *Sled =
+ SledMap.SledsIndex ? SledMap.SledsIndex[F - 1].fromPCRelative()
+ : findFunctionSleds(F, SledMap).Begin;
+ auto Addr = Sled->function();
+ auto PackedId = __xray_pack_id(F, Obj);
+
+
+ DataInfo DI;
+ Sym->SymbolizeData(Addr, &DI);
+
+ printf("Adding Entry: %d -> %x\n", PackedId, Addr);
+ printf("Symbol Info: function %s from module %s in %s:%s\n", DI.name, DI.module, DI.file, DI.line);
+
+ LastEntry->FunctionId = PackedId;
+ LastEntry->Addr = Addr;
+ LastEntry->Next = new FunctionMapEntry;
+ LastEntry = LastEntry->Next;
+ LastEntry->Next = nullptr;
+ }
+ }
+
+ return FMap;
+}
+
+int __xray_symbolize(int32_t PackedId, XRaySymbolInfo* SymInfo) {
+ if (!SymInfo) {
+ return 0; // TODO Error msg?
+ }
+
+ DataInfo DI;
+ bool Success = Symbolize(PackedId, &DI);
+ if (!Success) {
+ return false;
+ }
+
+ SymInfo->FuncId = PackedId;
+ SymInfo->Name = DI.name;
+ SymInfo->Module = DI.module;
+ SymInfo->File = DI.file;
+ SymInfo->Line = DI.line;
+
+ // TODO: DataInfo owns its memory, so passing char pointers is okay for now.
+ // Need to free at some point.
+
+ return true;
+}
+
XRayPatchingStatus __xray_patch() XRAY_NEVER_INSTRUMENT {
return controlPatching(true);
}
diff --git a/compiler-rt/lib/xray/xray_interface_internal.h b/compiler-rt/lib/xray/xray_interface_internal.h
index a8cfe0fde84dd..54ab2364a3382 100644
--- a/compiler-rt/lib/xray/xray_interface_internal.h
+++ b/compiler-rt/lib/xray/xray_interface_internal.h
@@ -20,6 +20,10 @@
#include <cstdint>
#include <utility>
+namespace __sanitizer {
+struct DataInfo;
+}
+
extern "C" {
// The following functions have to be defined in assembler, on a per-platform
// basis. See xray_trampoline_*.S files for implementations.
@@ -135,6 +139,8 @@ struct XRaySledMap {
bool Loaded;
};
+bool Symbolize(int32_t FuncId, DataInfo* DI);
+
bool patchFunctionEntry(bool Enable, uint32_t FuncId, const XRaySledEntry &Sled,
const XRayTrampolines &Trampolines, bool LogArgs);
bool patchFunctionExit(bool Enable, uint32_t FuncId, const XRaySledEntry &Sled,
diff --git a/compiler-rt/test/xray/TestCases/Posix/export-function-map.cpp b/compiler-rt/test/xray/TestCases/Posix/export-function-map.cpp
new file mode 100644
index 0000000000000..3001bcb9c2fa3
--- /dev/null
+++ b/compiler-rt/test/xray/TestCases/Posix/export-function-map.cpp
@@ -0,0 +1,57 @@
+// Check that we can export the global function map.
+//
+
+// RUN: split-file %s %t
+// RUN: %clangxx_xray -g -fPIC -fxray-instrument -fxray-shared -shared -std=c++11 %t/testlib.cpp -o %t/testlib.so
+// RUN: %clangxx_xray -g -fPIC -fxray-instrument -fxray-shared -std=c++11 %t/main.cpp %t/testlib.so -Wl,-rpath,%t -o %t/main.o
+
+// RUN: XRAY_OPTIONS="patch_premain=false" %run %t/main.o 2>&1 | FileCheck %s
+
+// REQUIRES: target={{(aarch64|x86_64)-.*}}
+
+//--- main.cpp
+
+#include "xray/xray_interface.h"
+
+#include <cstdio>
+
+bool called = false;
+
+void test_handler(int32_t fid, XRayEntryType type) {
+ printf("called: %d, type=%d\n", fid, static_cast<int32_t>(type));
+ called = true;
+}
+
+[[clang::xray_always_instrument]] void instrumented_in_executable() {
+ printf("instrumented_in_executable called\n");
+}
+
+extern void instrumented_in_dso();
+
+int main() {
+ __xray_set_handler(test_handler);
+ auto status = __xray_patch();
+ printf("patching status: %d\n", static_cast<int32_t>(status));
+ // CHECK: patching status: 1
+ instrumented_in_executable();
+ // CHECK-NEXT: called: {{.*}}, type=0
+ // CHECK-NEXT: instrumented_in_executable called
+ // CHECK-NEXT: called: {{.*}}, type=1
+ instrumented_in_dso();
+ // CHECK-NEXT: called: {{.*}}, type=0
+ // CHECK-NEXT: instrumented_in_dso called
+ // CHECK-NEXT: called: {{.*}}, type=1
+ status = __xray_unpatch();
+ printf("patching status: %d\n", static_cast<int32_t>(status));
+ // CHECK-NEXT: patching status: 1
+ auto map = __xray_export_function_map();
+ printf("Entry: %d -> %x\n", map->FunctionId, map->Addr);
+}
+
+//--- testlib.cpp
+
+#include <cstdio>
+
+[[clang::xray_always_instrument]] void instrumented_in_dso() {
+ printf("instrumented_in_dso called\n");
+}
>From f310c2848ba96645035c8eea6b317d158c103608 Mon Sep 17 00:00:00 2001
From: Sebastian Kreutzer <SebastianKreutzer at gmx.net>
Date: Tue, 19 Nov 2024 17:22:00 +0100
Subject: [PATCH 2/5] [XRay] Implement exporting symbols to trace
---
compiler-rt/include/xray/xray_interface.h | 2 +-
compiler-rt/include/xray/xray_records.h | 33 ++-
.../sanitizer_symbolizer_libcdep.cpp | 8 +-
.../sanitizer_symbolizer_posix_libcdep.cpp | 15 +-
compiler-rt/lib/xray/CMakeLists.txt | 3 +-
compiler-rt/lib/xray/xray_basic_logging.cpp | 247 +++++++++++++++---
compiler-rt/lib/xray/xray_interface.cpp | 127 ++++-----
.../lib/xray/xray_interface_internal.h | 6 +-
compiler-rt/lib/xray/xray_utils.cpp | 15 ++
compiler-rt/lib/xray/xray_utils.h | 2 +
.../xray/TestCases/Posix/basic-mode-dso.cpp | 7 +
.../TestCases/Posix/export-function-map.cpp | 5 +-
llvm/include/llvm/XRay/Trace.h | 40 +++
llvm/include/llvm/XRay/XRayRecord.h | 12 +
llvm/lib/XRay/Trace.cpp | 148 ++++++++++-
llvm/tools/llvm-xray/func-id-helper.cpp | 53 ++--
llvm/tools/llvm-xray/func-id-helper.h | 18 +-
llvm/tools/llvm-xray/xray-account.cpp | 28 +-
llvm/tools/llvm-xray/xray-account.h | 2 +-
19 files changed, 627 insertions(+), 144 deletions(-)
diff --git a/compiler-rt/include/xray/xray_interface.h b/compiler-rt/include/xray/xray_interface.h
index 277b792bdd8b6..9e6ebd6cf33f3 100644
--- a/compiler-rt/include/xray/xray_interface.h
+++ b/compiler-rt/include/xray/xray_interface.h
@@ -36,7 +36,7 @@ struct XRaySymbolInfo {
extern int __xray_symbolize(int32_t PackedId, XRaySymbolInfo* SymInfo);
-extern FunctionMapEntry* __xray_export_function_map();
+//extern FunctionMapEntry* __xray_export_function_map();
/// Synchronize this with AsmPrinter::SledKind in LLVM.
diff --git a/compiler-rt/include/xray/xray_records.h b/compiler-rt/include/xray/xray_records.h
index 8b82b6fb79cbc..5c87f21296226 100644
--- a/compiler-rt/include/xray/xray_records.h
+++ b/compiler-rt/include/xray/xray_records.h
@@ -68,15 +68,40 @@ static_assert(sizeof(XRayFileHeader) == 32, "XRayFileHeader != 32 bytes");
enum RecordTypes {
NORMAL = 0,
ARG_PAYLOAD = 1,
- FUNC_INFO = 2
+ FUNC_INFO = 2,
+ OBJ_INFO = 3,
+ FILE_MD = 4
};
-struct alignas(16) XRayFunctionInfoRecord {
+struct alignas(32) XRayFunctionMD {
uint16_t RecordType = RecordTypes::FUNC_INFO;
int32_t FuncId = 0;
+ int32_t Line = 0;
+ int16_t FileMDIdx = 0;
int16_t NameLen = 0;
- int16_t DemangledNameLen = 0;
- char Padding[6] = {};
+ // 18 bytes may not be enough to store the full name. In this case, 32 byte
+ // chunks containing the rest of the name are expected to follow this record
+ // as needed.
+ char NameBuffer[18] = {};
+} __attribute__((packed));
+
+struct alignas(32) XRayFileMD {
+ uint16_t RecordType = RecordTypes::FILE_MD;
+ int16_t FilenameLen = 0;
+ // The padding bytes may not be enough to store the full name. In this case, 32 byte blocks
+ // containing the rest of the name are expected to follow this record
+ // as needed.
+ char FilenameBuffer[28] = {};
+} __attribute__((packed));
+
+struct alignas(32) XRayObjectInfoRecord {
+ uint16_t RecordType = RecordTypes::OBJ_INFO;
+ int32_t ObjId = 0;
+ int16_t FilenameLen = 0;
+ // 24 may not be enough to store the full name. In this case, 32 byte blocks
+ // containing the rest of the name are expected to follow this record
+ // as needed.
+ char FilenameBuffer[24] = {};
} __attribute__((packed));
struct alignas(32) XRayRecord {
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cpp
index d4cfcb5690d3d..fe83be81fa9a0 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cpp
@@ -111,12 +111,18 @@ bool Symbolizer::SymbolizeData(uptr addr, DataInfo *info) {
info->module = internal_strdup(module_name);
info->module_offset = module_offset;
info->module_arch = arch;
+
+ Report("Trying out %d tools\n", tools_.size());
for (auto &tool : tools_) {
SymbolizerScope sym_scope(this);
if (tool.SymbolizeData(addr, info)) {
- return true;
+ Report("Symbolize tool produced data: function %s from module %s in %s:%s\n", info->name, info->module, info->file, info->line);
+ //return true;
+ } else {
+ Report("Tool failed\n");
}
}
+ return true; // FIXME Debugging
return false;
}
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp
index 0ddc24802d216..69e372e89cecc 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp
@@ -341,10 +341,16 @@ __sanitizer_symbolize_set_inline_frames(bool InlineFrames);
class InternalSymbolizer final : public SymbolizerTool {
public:
static InternalSymbolizer *get(LowLevelAllocator *alloc) {
+ if (&__sanitizer_symbolize_code == nullptr) {
+ VReport(2, "interal symbolizer not linked!\n");
+ }
// These one is the most used one, so we will use it to detect a presence of
// internal symbolizer.
- if (&__sanitizer_symbolize_code == nullptr)
+ if (&__sanitizer_symbolize_code == nullptr) {
return nullptr;
+ }
+
+
CHECK(__sanitizer_symbolize_set_demangle(common_flags()->demangle));
CHECK(__sanitizer_symbolize_set_inline_frames(
common_flags()->symbolize_inline_frames));
@@ -465,6 +471,7 @@ static SymbolizerTool *ChooseExternalSymbolizer(LowLevelAllocator *allocator) {
static void ChooseSymbolizerTools(IntrusiveList<SymbolizerTool> *list,
LowLevelAllocator *allocator) {
+ VReport(2, "Choosing symbolizer\n");
if (!common_flags()->symbolize) {
VReport(2, "Symbolizer is disabled.\n");
return;
@@ -480,12 +487,14 @@ static void ChooseSymbolizerTools(IntrusiveList<SymbolizerTool> *list,
} else if (SymbolizerTool *tool = InternalSymbolizer::get(allocator)) {
VReport(2, "Using internal symbolizer.\n");
list->push_back(tool);
- return;
+// return;
+ } else {
+ VReport(2, "Cannot instantiate internal symbolizer!\n");
}
if (SymbolizerTool *tool = LibbacktraceSymbolizer::get(allocator)) {
VReport(2, "Using libbacktrace symbolizer.\n");
list->push_back(tool);
- return;
+// return;
}
if (SymbolizerTool *tool = ChooseExternalSymbolizer(allocator)) {
diff --git a/compiler-rt/lib/xray/CMakeLists.txt b/compiler-rt/lib/xray/CMakeLists.txt
index ea9e10978e3e9..1ea65041b6509 100644
--- a/compiler-rt/lib/xray/CMakeLists.txt
+++ b/compiler-rt/lib/xray/CMakeLists.txt
@@ -214,7 +214,8 @@ add_compiler_rt_component(xray)
set(XRAY_COMMON_RUNTIME_OBJECT_LIBS
RTSanitizerCommon
RTSanitizerCommonLibc
- RTSanitizerCommonSymbolizer)
+ RTSanitizerCommonSymbolizer
+ RTSanitizerCommonSymbolizerInternal)
# XRay uses C++ standard library headers.
if (TARGET cxx-headers OR HAVE_LIBCXX)
diff --git a/compiler-rt/lib/xray/xray_basic_logging.cpp b/compiler-rt/lib/xray/xray_basic_logging.cpp
index 1be59a277a402..9ba310db3de07 100644
--- a/compiler-rt/lib/xray/xray_basic_logging.cpp
+++ b/compiler-rt/lib/xray/xray_basic_logging.cpp
@@ -29,7 +29,9 @@
#include "sanitizer_common/sanitizer_libc.h"
#include "sanitizer_common/sanitizer_dense_map.h"
#include "sanitizer_common/sanitizer_symbolizer.h"
+#include "sanitizer_common/sanitizer_hash.h"
#include "xray/xray_records.h"
+#include "xray/xray_allocator.h"
#include "xray_recursion_guard.h"
#include "xray_basic_flags.h"
#include "xray_basic_logging.h"
@@ -39,13 +41,63 @@
#include "xray_tsc.h"
#include "xray_utils.h"
+#include <new>
+
+namespace {
+struct StringKey {
+ constexpr StringKey() {}
+ constexpr StringKey(const char *Key) : Key(Key), EmptyOrTombstone(1) {}
+
+ static constexpr StringKey Empty() {
+ StringKey Key;
+ Key.EmptyOrTombstone = __sanitizer::DenseMapInfo<char>::getEmptyKey();
+ return Key;
+ }
+
+ static constexpr StringKey Tombstone() {
+ StringKey Key;
+ Key.EmptyOrTombstone = __sanitizer::DenseMapInfo<char>::getTombstoneKey();
+ return Key;
+ }
+
+ const char *Key{nullptr};
+ mutable char EmptyOrTombstone{__sanitizer::DenseMapInfo<char>::getEmptyKey()};
+
+};
+} // namespace
+
+namespace __sanitizer {
+// Provide DenseMapInfo for chars.
+template <> struct DenseMapInfo<StringKey> {
+ static constexpr StringKey getEmptyKey() { return StringKey::Empty(); }
+ static constexpr StringKey getTombstoneKey() { return StringKey::Tombstone(); }
+ static unsigned getHashValue(const StringKey &Val) {
+ if (!Val.Key) {
+ return 0;
+ }
+ MurMur2HashBuilder Hash;
+ auto Len = internal_strlen(Val.Key);
+ for (unsigned I = 0; I < Len; I++) {
+ Hash.add(DenseMapInfo<char>::getHashValue(Val.Key[I]));
+ }
+ return Hash.get();
+ }
+
+ static bool isEqual(const StringKey &LHS, const StringKey &RHS) {
+ if (!LHS.Key || !RHS.Key) {
+ return !LHS.Key && !RHS.Key;
+ }
+ return __sanitizer::internal_strcmp(LHS.Key, RHS.Key) == 0;
+ }
+};
+} // namespace __sanitizer
+
namespace __xray {
static SpinMutex LogMutex;
namespace {
-
// We use elements of this type to record the entry TSC of every function ID we
// see as we're tracing a particular thread's execution.
struct alignas(16) StackEntry {
@@ -89,6 +141,136 @@ static atomic_uint64_t TicksPerSec{0};
static atomic_uint64_t CycleFrequency{NanosecondsPerSecond};
+struct FunctionRecordBuffer {
+
+ // First entry is buffer idx, second states if this entry has been flushed.
+ using FuncMapEntry = bool;//detail::DenseMapPair<int32_t, bool>;
+
+ // DenseMap<int32_t, DataInfo> SymInfo;
+
+ // Using this like a set to track which function have been symbolized.
+ DenseMap<int32_t, FuncMapEntry> FuncMapping;
+
+ using MappedAddressInfo = std::pair<int, AddressInfo>;
+
+ MappedAddressInfo * AddrInfoBuf{nullptr};
+ unsigned Size{0};
+
+ DenseMap<StringKey, int32_t> FileMDMap;
+ unsigned FileMDCount{0};
+
+ DenseMap<int32_t, bool> ObjWrittenMap;
+
+ static constexpr unsigned BufferSize = 1024;
+
+ LogWriter* Writer;
+
+ FunctionRecordBuffer(LogWriter* LW) XRAY_NEVER_INSTRUMENT : Writer(LW) {
+ AddrInfoBuf = allocateBuffer<MappedAddressInfo>(BufferSize);
+ }
+
+ ~FunctionRecordBuffer() XRAY_NEVER_INSTRUMENT {
+ Flush();
+ deallocateBuffer<MappedAddressInfo>(AddrInfoBuf, BufferSize);
+ }
+
+ static FunctionRecordBuffer& Create(LogWriter* LW) XRAY_NEVER_INSTRUMENT {
+ auto *FRB = allocate<FunctionRecordBuffer>();
+ new (FRB) FunctionRecordBuffer(LW);
+ return *FRB;
+ }
+
+ void Destroy() XRAY_NEVER_INSTRUMENT {
+ this->~FunctionRecordBuffer();
+ deallocate(this);
+ }
+
+ void StoreFunctionRecord(int32_t FuncId) XRAY_NEVER_INSTRUMENT {
+
+ auto& Symbolized = FuncMapping[FuncId];
+ if (!Symbolized) {
+ if (Size >= BufferSize) {
+ Flush();
+ }
+ auto&MAI = AddrInfoBuf[Size];
+ if (!Symbolize(FuncId, &MAI.second)) {
+ Report("Unable to symbolize function %d\n", FuncId);
+ return;
+ }
+ MAI.first = FuncId;
+ Symbolized = true;
+ Size++;
+ }
+
+
+ }
+
+ void Flush() XRAY_NEVER_INSTRUMENT {
+ if (Verbosity())
+ Report("Flushing function record buffer\n");
+ for (unsigned I = 0; I < Size; I++) {
+ auto& MDI = AddrInfoBuf[I];
+ auto Id = MDI.first;
+ AddressInfo& AI = MDI.second;
+
+ int FileMDIdx = 0;
+
+ // TODO: Does this work with strings?
+ if (auto *It = FileMDMap.find(StringKey(AI.file)); It) {
+ FileMDIdx = It->second;
+ } else {
+ XRayFileMD FMD;
+ FMD.FilenameLen = static_cast<int16_t>(internal_strlen(AI.file));
+ Writer->WriteAll(reinterpret_cast<char *>(&FMD),
+ reinterpret_cast<char *>(&FMD.FilenameBuffer));
+ Writer->WriteAll(AI.file, AI.file + FMD.FilenameLen);
+ constexpr int FilenameBufferSize = sizeof(FMD.FilenameBuffer);
+ auto NumPaddingBytes = FMD.FilenameLen < FilenameBufferSize ? FilenameBufferSize - FMD.FilenameLen : 32 - (FMD.FilenameLen - FilenameBufferSize) % 32;
+ Writer->WritePadding(NumPaddingBytes);
+ FileMDMap[AI.file] = FileMDCount;
+ FileMDIdx = FileMDCount;
+ FileMDCount++;
+ }
+
+ XRayFunctionMD FIR;
+ FIR.FuncId = Id;
+ FIR.FileMDIdx = FileMDIdx;
+ FIR.Line = AI.line;
+ FIR.NameLen = static_cast<int16_t>(internal_strlen(AI.function));
+ // The padding bytes are used for string storage.
+ Writer->WriteAll(reinterpret_cast<char *>(&FIR),
+ reinterpret_cast<char *>(&FIR.NameBuffer));
+ Writer->WriteAll(AI.function, AI.function + FIR.NameLen);
+ constexpr int NameBufferSize = sizeof(FIR.NameBuffer);
+ auto NumPaddingBytes = FIR.NameLen < NameBufferSize ? NameBufferSize - FIR.NameLen : 32 - (FIR.NameLen - NameBufferSize) % 32;
+ Report("Writing string %s (length %d) for ID %d, adding padding bytes: %d\n",
+ AI.function, FIR.NameLen, FIR.FuncId, NumPaddingBytes);
+ Writer->WritePadding(NumPaddingBytes);
+
+// auto ObjId = UnpackId(Id).first;
+// auto& ObjWritten = ObjWrittenMap[ObjId];
+// if (!ObjWritten) {
+// XRayObjectInfoRecord OIR;
+// OIR.ObjId = ObjId;
+// const char* Filename = AI.module;
+// OIR.FilenameLen = static_cast<int16_t>(internal_strlen(Filename));
+// Writer->WriteAll(reinterpret_cast<char *>(&OIR),
+// reinterpret_cast<char *>(&OIR.FilenameBuffer));
+// Writer->WriteAll(Filename, Filename + OIR.FilenameLen);
+// NumPaddingBytes = OIR.FilenameLen < 24 ? 24 - OIR.FilenameLen : 32 - (OIR.FilenameLen - 24) % 32;
+// Writer->WritePadding(NumPaddingBytes);
+// ObjWritten = true;
+// }
+ }
+ Size = 0;
+ }
+};
+
+
+struct GlobalLoggingData {
+ LogWriter* Writer;
+ FunctionRecordBuffer* RecordBuffer;
+};
static LogWriter *getLog() XRAY_NEVER_INSTRUMENT {
LogWriter* LW = LogWriter::Open();
@@ -120,11 +302,17 @@ static LogWriter *getLog() XRAY_NEVER_INSTRUMENT {
return LW;
}
-static LogWriter *getGlobalLog() XRAY_NEVER_INSTRUMENT {
+static GlobalLoggingData createLoggingData() XRAY_NEVER_INSTRUMENT {
+ auto* LW = getLog();
+ auto* FRB = &FunctionRecordBuffer::Create(LW);
+ return {LW, FRB};
+}
+
+static GlobalLoggingData &getGlobalData() XRAY_NEVER_INSTRUMENT {
static pthread_once_t OnceInit = PTHREAD_ONCE_INIT;
- static LogWriter *LW = nullptr;
- pthread_once(&OnceInit, +[] { LW = getLog(); });
- return LW;
+ static GlobalLoggingData LD;
+ pthread_once(&OnceInit, +[] { LD = createLoggingData(); });
+ return LD;
}
static ThreadLocalData &getThreadLocalData() XRAY_NEVER_INSTRUMENT {
@@ -136,7 +324,7 @@ static ThreadLocalData &getThreadLocalData() XRAY_NEVER_INSTRUMENT {
return false;
}
pthread_setspecific(PThreadKey, &TLD);
- TLD.LogWriter = getGlobalLog();
+ TLD.LogWriter = getGlobalData().Writer;
TLD.InMemoryBuffer = reinterpret_cast<XRayRecord *>(
InternalAlloc(sizeof(XRayRecord) * GlobalOptions.ThreadBufferSize,
nullptr, alignof(XRayRecord)));
@@ -160,45 +348,14 @@ static ThreadLocalData &getThreadLocalData() XRAY_NEVER_INSTRUMENT {
return TLD;
}
-struct FunctionRecordLogger {
- DenseMap<int32_t, DataInfo> SymInfo;
-
- static FunctionRecordLogger& Get() {
- static FunctionRecordLogger Instance;
- return Instance;
- }
-
- static void LogFunctionRecord(int32_t FuncId) {
- auto& Instance = Get();
- if (Instance.SymInfo.contains(FuncId)) {
- return;
- }
-
- auto& Entry = Instance.SymInfo[FuncId];
- Symbolize(FuncId, &Entry);
- // TODO: handle error
-
- }
-
- static void Flush(LogWriter* Writer) {
- auto& Instance = Get();
- Instance.SymInfo.forEach([&](auto& Entry) {
- XRayFunctionInfoRecord FIR;
- auto& Id = Entry.getFirst();
- DataInfo& DI = Entry.getSecond();
- FIR.FuncId = Id;
- FIR.NameLen = internal_strlen(DI.name);
- FIR.DemangledNameLen = internal_strlen(DI.name);
- });
- Writer->WriteAll();
- }
-};
template <class RDTSC>
void InMemoryRawLog(int32_t FuncId, XRayEntryType Type,
RDTSC ReadTSC) XRAY_NEVER_INSTRUMENT {
auto &TLD = getThreadLocalData();
- LogWriter *LW = getGlobalLog();
+ auto &GD = getGlobalData();
+
+ LogWriter *LW = GD.Writer;
if (LW == nullptr)
return;
@@ -270,6 +427,8 @@ void InMemoryRawLog(int32_t FuncId, XRayEntryType Type,
break;
}
+ // Add function record
+ GD.RecordBuffer->StoreFunctionRecord(FuncId);
// First determine whether the delta between the function's enter record and
// the exit record is higher than the threshold.
@@ -299,7 +458,7 @@ void InMemoryRawLogWithArg(int32_t FuncId, XRayEntryType Type, uint64_t Arg1,
auto FirstEntry =
reinterpret_cast<XRayArgPayload *>(TLD.InMemoryBuffer);
const auto &BuffLen = TLD.BufferSize;
- LogWriter *LW = getGlobalLog();
+ LogWriter *LW = getGlobalData().Writer;
if (LW == nullptr)
return;
@@ -408,6 +567,7 @@ static void TLDDestructor(void *P) XRAY_NEVER_INSTRUMENT {
// sync instead and hope that the pending writes are flushed as the
// thread exits.
TLD.LogWriter->Flush();
+ getGlobalData().RecordBuffer->Flush();
}
XRayLogInitStatus basicLoggingInit(UNUSED size_t BufferSize,
@@ -490,6 +650,11 @@ XRayLogInitStatus basicLoggingFinalize() XRAY_NEVER_INSTRUMENT {
// Nothing really to do aside from marking state of the global to be
// uninitialized.
+ if (Verbosity())
+ Report("Finalizing basic mode\n");
+
+ getGlobalData().RecordBuffer->Flush();
+
return XRayLogInitStatus::XRAY_LOG_FINALIZED;
}
diff --git a/compiler-rt/lib/xray/xray_interface.cpp b/compiler-rt/lib/xray/xray_interface.cpp
index c2d34185290cd..275390ad09d05 100644
--- a/compiler-rt/lib/xray/xray_interface.cpp
+++ b/compiler-rt/lib/xray/xray_interface.cpp
@@ -508,7 +508,7 @@ XRayPatchingStatus mprotectAndPatchFunction(int32_t FuncId, int32_t ObjId,
} // namespace
-bool Symbolize(int32_t PackedId, DataInfo* DI) {
+bool Symbolize(int32_t PackedId, AddressInfo* AI) {
auto Ids = UnpackId(PackedId);
auto ObjId = Ids.first;
auto FuncId = Ids.second;
@@ -522,14 +522,23 @@ bool Symbolize(int32_t PackedId, DataInfo* DI) {
auto Addr = Sled->function();
Symbolizer* Sym = Symbolizer::GetOrInit();
- Sym->RefreshModules(); // FIXME: When is this needed?
-
- auto Status = Sym->SymbolizeData(Addr, DI);
+// Sym->RefreshModules(); // FIXME: Is this needed?
+ auto* SymStack = Sym->SymbolizePC(Addr);
+ if (!SymStack) {
+ return false;
+ }
printf("Adding Entry: %d -> %x\n", PackedId, Addr);
- printf("Symbol Info: function %s from module %s in %s:%s\n", DI.name, DI.module, DI.file, DI.line);
+// printf("Symbol Info: function %s from module %s in %s:%s\n", DI->name, DI->module, DI->file, DI->line);
+
+
+ printf("Symbol Info (stack): function %s from module %s in %s:%d\n", SymStack->info.function, SymStack->info.module, SymStack->info.file, SymStack->info.line);
- return Status;
+ // XRay does not support inlined function instrumentation.
+ // Therefor we only look at the first function stack entry.
+ *AI = SymStack->info;
+
+ return true;
}
@@ -594,70 +603,70 @@ uint16_t __xray_register_event_type(
return h->type_id;
}
-FunctionMapEntry* __xray_export_function_map() {
- if (!atomic_load(&XRayInitialized, memory_order_acquire))
- return {};
-
- SpinMutexLock Guard(&XRayInstrMapMutex);
-
- // No atomic load necessary since we have acquired the mutex
- uint32_t NumObjects = atomic_load(&XRayNumObjects, memory_order_acquire);
-
- FunctionMapEntry* FMap = new FunctionMapEntry;
- FMap->Next = nullptr;
-
- Symbolizer* Sym = Symbolizer::GetOrInit();
- Sym->RefreshModules();
-
-
- printf("Objects: %d\n", NumObjects);
-
-
- FunctionMapEntry* LastEntry = FMap;
- for (int Obj = 0; Obj < NumObjects; Obj++) {
- auto& SledMap = XRayInstrMaps[Obj];
- printf("Functions (%d): %d\n", Obj, SledMap.Functions);
- for (int F = 1; F <= SledMap.Functions; F++) {
- const XRaySledEntry *Sled =
- SledMap.SledsIndex ? SledMap.SledsIndex[F - 1].fromPCRelative()
- : findFunctionSleds(F, SledMap).Begin;
- auto Addr = Sled->function();
- auto PackedId = __xray_pack_id(F, Obj);
-
-
- DataInfo DI;
- Sym->SymbolizeData(Addr, &DI);
-
- printf("Adding Entry: %d -> %x\n", PackedId, Addr);
- printf("Symbol Info: function %s from module %s in %s:%s\n", DI.name, DI.module, DI.file, DI.line);
-
- LastEntry->FunctionId = PackedId;
- LastEntry->Addr = Addr;
- LastEntry->Next = new FunctionMapEntry;
- LastEntry = LastEntry->Next;
- LastEntry->Next = nullptr;
- }
- }
-
- return FMap;
-}
+//FunctionMapEntry* __xray_export_function_map() {
+// if (!atomic_load(&XRayInitialized, memory_order_acquire))
+// return {};
+//
+// SpinMutexLock Guard(&XRayInstrMapMutex);
+//
+// // No atomic load necessary since we have acquired the mutex
+// uint32_t NumObjects = atomic_load(&XRayNumObjects, memory_order_acquire);
+//
+// FunctionMapEntry* FMap = new FunctionMapEntry;
+// FMap->Next = nullptr;
+//
+// Symbolizer* Sym = Symbolizer::GetOrInit();
+// Sym->RefreshModules();
+//
+//
+// printf("Objects: %d\n", NumObjects);
+//
+//
+// FunctionMapEntry* LastEntry = FMap;
+// for (int Obj = 0; Obj < NumObjects; Obj++) {
+// auto& SledMap = XRayInstrMaps[Obj];
+// printf("Functions (%d): %d\n", Obj, SledMap.Functions);
+// for (int F = 1; F <= SledMap.Functions; F++) {
+// const XRaySledEntry *Sled =
+// SledMap.SledsIndex ? SledMap.SledsIndex[F - 1].fromPCRelative()
+// : findFunctionSleds(F, SledMap).Begin;
+// auto Addr = Sled->function();
+// auto PackedId = __xray_pack_id(F, Obj);
+//
+//
+// DataInfo DI;
+// Sym->SymbolizeData(Addr, &DI);
+//
+// printf("Adding Entry: %d -> %x\n", PackedId, Addr);
+// printf("Symbol Info: function %s from module %s in %s:%s\n", DI.name, DI.module, DI.file, DI.line);
+//
+// LastEntry->FunctionId = PackedId;
+// LastEntry->Addr = Addr;
+// LastEntry->Next = new FunctionMapEntry;
+// LastEntry = LastEntry->Next;
+// LastEntry->Next = nullptr;
+// }
+// }
+//
+// return FMap;
+//}
int __xray_symbolize(int32_t PackedId, XRaySymbolInfo* SymInfo) {
if (!SymInfo) {
return 0; // TODO Error msg?
}
- DataInfo DI;
- bool Success = Symbolize(PackedId, &DI);
+ AddressInfo ai;
+ bool Success = Symbolize(PackedId, &ai);
if (!Success) {
return false;
}
SymInfo->FuncId = PackedId;
- SymInfo->Name = DI.name;
- SymInfo->Module = DI.module;
- SymInfo->File = DI.file;
- SymInfo->Line = DI.line;
+ SymInfo->Name = ai.function;
+ SymInfo->Module = ai.module;
+ SymInfo->File = ai.file;
+ SymInfo->Line = ai.line;
// TODO: DataInfo owns its memory, so passing char pointers is okay for now.
// Need to free at some point.
diff --git a/compiler-rt/lib/xray/xray_interface_internal.h b/compiler-rt/lib/xray/xray_interface_internal.h
index 54ab2364a3382..ca1618a8fcc1c 100644
--- a/compiler-rt/lib/xray/xray_interface_internal.h
+++ b/compiler-rt/lib/xray/xray_interface_internal.h
@@ -15,14 +15,12 @@
#define XRAY_INTERFACE_INTERNAL_H
#include "sanitizer_common/sanitizer_platform.h"
+#include "sanitizer_common/sanitizer_symbolizer.h"
#include "xray/xray_interface.h"
#include <cstddef>
#include <cstdint>
#include <utility>
-namespace __sanitizer {
-struct DataInfo;
-}
extern "C" {
// The following functions have to be defined in assembler, on a per-platform
@@ -139,7 +137,7 @@ struct XRaySledMap {
bool Loaded;
};
-bool Symbolize(int32_t FuncId, DataInfo* DI);
+bool Symbolize(int32_t FuncId, AddressInfo* DI);
bool patchFunctionEntry(bool Enable, uint32_t FuncId, const XRaySledEntry &Sled,
const XRayTrampolines &Trampolines, bool LogArgs);
diff --git a/compiler-rt/lib/xray/xray_utils.cpp b/compiler-rt/lib/xray/xray_utils.cpp
index 5d51df9937c2c..38fef4553ff91 100644
--- a/compiler-rt/lib/xray/xray_utils.cpp
+++ b/compiler-rt/lib/xray/xray_utils.cpp
@@ -155,6 +155,21 @@ void LogWriter::WriteAll(const char *Begin, const char *End) XRAY_NEVER_INSTRUME
}
}
+void LogWriter::WritePadding(int NumBytes) {
+ // TODO: There is probably a more efficient way to do this
+ const char PaddingChar = '\0';
+ while (NumBytes > 0) {
+ auto Written = write(Fd, &PaddingChar, 1);
+ if (Written < 0) {
+ if (errno == EINTR)
+ continue; // Try again.
+ Report("Failed to write; errno = %d\n", errno);
+ return;
+ }
+ NumBytes--;
+ }
+}
+
void LogWriter::Flush() XRAY_NEVER_INSTRUMENT {
fsync(Fd);
}
diff --git a/compiler-rt/lib/xray/xray_utils.h b/compiler-rt/lib/xray/xray_utils.h
index 5dc73d7fa8cde..a8f70346bf571 100644
--- a/compiler-rt/lib/xray/xray_utils.h
+++ b/compiler-rt/lib/xray/xray_utils.h
@@ -38,6 +38,8 @@ class LogWriter {
// Write a character range into a log.
void WriteAll(const char *Begin, const char *End);
+ void WritePadding(int NumBytes);
+
void Flush();
// Returns a new log instance initialized using the flag-provided values.
diff --git a/compiler-rt/test/xray/TestCases/Posix/basic-mode-dso.cpp b/compiler-rt/test/xray/TestCases/Posix/basic-mode-dso.cpp
index d40dcd808bcba..acabe03b51eb4 100644
--- a/compiler-rt/test/xray/TestCases/Posix/basic-mode-dso.cpp
+++ b/compiler-rt/test/xray/TestCases/Posix/basic-mode-dso.cpp
@@ -39,10 +39,17 @@ int main() {
#include <cstdio>
#include <unistd.h>
+[[clang::xray_always_instrument]] void instrumented_in_dso2() {
+ printf("instrumented_in_dso2 called\n");
+}
+
+
[[clang::xray_always_instrument]] void instrumented_in_dso() {
printf("instrumented_in_dso called\n");
+ instrumented_in_dso2();
}
+
// ACCOUNT: funcid,count,min,median,90%ile,99%ile,max,sum,debug,function
// ACCOUNT-NEXT: 1,1,{{.*}}
// ACCOUNT-NEXT: 16777217,1,{{.*}}
diff --git a/compiler-rt/test/xray/TestCases/Posix/export-function-map.cpp b/compiler-rt/test/xray/TestCases/Posix/export-function-map.cpp
index 3001bcb9c2fa3..c2706d43ee777 100644
--- a/compiler-rt/test/xray/TestCases/Posix/export-function-map.cpp
+++ b/compiler-rt/test/xray/TestCases/Posix/export-function-map.cpp
@@ -44,8 +44,9 @@ int main() {
status = __xray_unpatch();
printf("patching status: %d\n", static_cast<int32_t>(status));
// CHECK-NEXT: patching status: 1
- auto map = __xray_export_function_map();
- printf("Entry: %d -> %x\n", map->FunctionId, map->Addr);
+ // FIXME
+// auto map = __xray_export_function_map();
+// printf("Entry: %d -> %x\n", map->FunctionId, map->Addr);
}
//--- testlib.cpp
diff --git a/llvm/include/llvm/XRay/Trace.h b/llvm/include/llvm/XRay/Trace.h
index eb1f03b2a0d4a..9c69b950fdcdf 100644
--- a/llvm/include/llvm/XRay/Trace.h
+++ b/llvm/include/llvm/XRay/Trace.h
@@ -23,6 +23,40 @@
namespace llvm {
namespace xray {
+class Trace;
+
+class FunctionMetadata {
+
+ using FuncInfoVector = std::vector<XRayFunctionInfo>;
+ FuncInfoVector FuncMapping;
+
+ using ObjInfoVector = std::vector<XRayObjectInfo>;
+ ObjInfoVector ObjInfo;
+
+ typedef std::vector<XRayFunctionInfo>::const_iterator fmap_citerator;
+
+ typedef std::vector<XRayObjectInfo>::const_iterator omap_citerator;
+
+public:
+ bool hasFunctionMapping() const { return FuncMapping.empty();}
+ bool hasObjectInfo() const {return ObjInfo.empty();}
+
+ void AddFunctionInfo(XRayFunctionInfo FInfo) {
+ FuncMapping.push_back(std::move(FInfo));
+ }
+
+ void AddObjectInfo(XRayObjectInfo OInfo) {
+ ObjInfo.push_back(std::move(OInfo));
+ }
+
+ fmap_citerator mapping_begin() const { return FuncMapping.cbegin(); }
+ fmap_citerator mappping_end() const { return FuncMapping.cend(); }
+
+ omap_citerator objects_begin() const { return ObjInfo.cbegin(); }
+ omap_citerator objects_end() const { return ObjInfo.cend(); }
+
+};
+
/// A Trace object represents the records that have been loaded from XRay
/// log files generated by instrumented binaries. We encapsulate the logic of
/// reading the traces in factory functions that populate the Trace object
@@ -48,6 +82,8 @@ class Trace {
using RecordVector = std::vector<XRayRecord>;
RecordVector Records;
+ FunctionMetadata FuncMetadata;
+
typedef std::vector<XRayRecord>::const_iterator citerator;
friend Expected<Trace> loadTrace(const DataExtractor &, bool);
@@ -60,10 +96,14 @@ class Trace {
/// Provides access to the loaded XRay trace file header.
const XRayFileHeader &getFileHeader() const { return FileHeader; }
+ const FunctionMetadata &getFunctionMetadata() const { return FuncMetadata;}
+
const_iterator begin() const { return Records.begin(); }
const_iterator end() const { return Records.end(); }
bool empty() const { return Records.empty(); }
size_type size() const { return Records.size(); }
+
+
};
/// This function will attempt to load XRay trace records from the provided
diff --git a/llvm/include/llvm/XRay/XRayRecord.h b/llvm/include/llvm/XRay/XRayRecord.h
index 238bf3daf6ea5..4aa88de225be0 100644
--- a/llvm/include/llvm/XRay/XRayRecord.h
+++ b/llvm/include/llvm/XRay/XRayRecord.h
@@ -98,6 +98,18 @@ struct XRayRecord {
std::string Data;
};
+struct XRayFunctionInfo {
+ int32_t FuncId;
+ std::string Name;
+ int32_t Line;
+ std::string File;
+};
+
+struct XRayObjectInfo {
+ int32_t ObjId;
+ std::string Filename;
+};
+
} // namespace xray
} // namespace llvm
diff --git a/llvm/lib/XRay/Trace.cpp b/llvm/lib/XRay/Trace.cpp
index 74515b16417da..bcb7d5460bf82 100644
--- a/llvm/lib/XRay/Trace.cpp
+++ b/llvm/lib/XRay/Trace.cpp
@@ -33,7 +33,8 @@ namespace {
Error loadNaiveFormatLog(StringRef Data, bool IsLittleEndian,
XRayFileHeader &FileHeader,
- std::vector<XRayRecord> &Records) {
+ std::vector<XRayRecord> &Records,
+ FunctionMetadata &FuncMetadata) {
if (Data.size() < 32)
return make_error<StringError>(
"Not enough bytes for an XRay log.",
@@ -54,6 +55,8 @@ Error loadNaiveFormatLog(StringRef Data, bool IsLittleEndian,
size_t NumReservations = llvm::divideCeil(Reader.size() - OffsetPtr, 32U);
Records.reserve(NumReservations);
+ llvm::SmallVector<std::string, 8> Filenames;
+
// Each record after the header will be 32 bytes, in the following format:
//
// (2) uint16 : record type
@@ -198,6 +201,146 @@ Error loadNaiveFormatLog(StringRef Data, bool IsLittleEndian,
Record.CallArgs.push_back(Arg);
break;
}
+ case 2: { // Function info record.
+
+ XRayFunctionInfo Info;
+
+ auto FInfoBeginOffset = OffsetPtr;
+ PreReadOffset = OffsetPtr;
+ int32_t FuncId = Reader.getSigned(&OffsetPtr, sizeof(int32_t));
+ if (OffsetPtr == PreReadOffset)
+ return createStringError(
+ std::make_error_code(std::errc::executable_format_error),
+ "Failed reading function id field at offset %" PRId64 ".",
+ OffsetPtr);
+ Info.FuncId = FuncId;
+
+ PreReadOffset = OffsetPtr;
+ int32_t Line = Reader.getSigned(&OffsetPtr, sizeof(int32_t));
+ if (OffsetPtr == PreReadOffset)
+ return createStringError(
+ std::make_error_code(std::errc::executable_format_error),
+ "Failed reading function id field at offset %" PRId64 ".",
+ OffsetPtr);
+ Info.Line = Line;
+
+ PreReadOffset = OffsetPtr;
+ int16_t FileMDIdx = Reader.getSigned(&OffsetPtr, sizeof(int16_t));
+ if (OffsetPtr == PreReadOffset)
+ return createStringError(
+ std::make_error_code(std::errc::executable_format_error),
+ "Failed reading file metadata field at offset %" PRId64 ".",
+ OffsetPtr);
+ if (FileMDIdx < 0 || static_cast<size_t>(FileMDIdx) >= Filenames.size()) {
+ return createStringError(
+ std::make_error_code(std::errc::executable_format_error),
+ "File metadata does not exist at offset %" PRId64 ".",
+ OffsetPtr);
+ }
+ outs() << "MD index is: " << FileMDIdx << "\n";
+ Info.File = Filenames[FileMDIdx];
+
+ PreReadOffset = OffsetPtr;
+ auto NameLen = Reader.getU16(&OffsetPtr);
+ if (OffsetPtr == PreReadOffset)
+ return createStringError(
+ std::make_error_code(std::errc::executable_format_error),
+ "Failed reading symbol length at offset %" PRId64 ".", OffsetPtr);
+
+
+ PreReadOffset = OffsetPtr;
+ auto FName = Reader.getFixedLengthString(&OffsetPtr, NameLen);
+ if (OffsetPtr == PreReadOffset)
+ return createStringError(
+ std::make_error_code(std::errc::executable_format_error),
+ "Failed reading symbol %" PRId64 ".", OffsetPtr);
+ Info.Name = FName;
+
+ FuncMetadata.AddFunctionInfo(Info);
+
+ llvm::outs() << "Read function: " << FuncId << ": " << FName << "\n";
+
+ // Skip to start of next 32 byte record. Subtract 8 to main to account
+ // for 8 byte advance after switch.
+ auto BytesUsedInChunk = (OffsetPtr - FInfoBeginOffset + 2) % 32;
+ auto BytesToSkip =
+ BytesUsedInChunk > 0 ? 32 - BytesUsedInChunk % 32 : 0;
+ OffsetPtr += BytesToSkip - 8;
+ break;
+ }
+ case 3: // Object info record
+ {
+ llvm_unreachable("Handling removed");
+// XRayObjectInfo ObjInfo;
+//
+// auto OInfoBeginOffset = OffsetPtr;
+// PreReadOffset = OffsetPtr;
+// int32_t ObjId = Reader.getSigned(&OffsetPtr, sizeof(int32_t));
+// if (OffsetPtr == PreReadOffset)
+// return createStringError(
+// std::make_error_code(std::errc::executable_format_error),
+// "Failed reading object id field at offset %" PRId64 ".",
+// OffsetPtr);
+//
+// ObjInfo.ObjId = ObjId;
+//
+// PreReadOffset = OffsetPtr;
+// auto NameLen = Reader.getU16(&OffsetPtr);
+// if (OffsetPtr == PreReadOffset)
+// return createStringError(
+// std::make_error_code(std::errc::executable_format_error),
+// "Failed reading symbol length at offset %" PRId64 ".", OffsetPtr);
+//
+//
+// PreReadOffset = OffsetPtr;
+// auto Filename = Reader.getFixedLengthString(&OffsetPtr, NameLen);
+// if (OffsetPtr == PreReadOffset)
+// return createStringError(
+// std::make_error_code(std::errc::executable_format_error),
+// "Failed reading symbol %" PRId64 ".", OffsetPtr);
+// ObjInfo.Filename = Filename;
+//
+// FuncMetadata.AddObjectInfo(ObjInfo);
+//
+// llvm::outs() << "Read object: " << ObjId << ": " << Filename << "\n";
+//
+// // Skip to start of next 32 byte record. Subtract 8 to main to account
+// // for 8 byte advance after switch.
+// auto BytesUsedInChunk = (OffsetPtr - OInfoBeginOffset + 2) % 32;
+// auto BytesToSkip =
+// BytesUsedInChunk > 0 ? 32 - BytesUsedInChunk % 32 : 0;
+// OffsetPtr += BytesToSkip - 8;
+ break;
+ }
+ case 4: // Filename MD
+ {
+ auto FilenameBeginOffset = OffsetPtr;
+ PreReadOffset = OffsetPtr;
+ auto NameLen = Reader.getU16(&OffsetPtr);
+ if (OffsetPtr == PreReadOffset)
+ return createStringError(
+ std::make_error_code(std::errc::executable_format_error),
+ "Failed reading filename length at offset %" PRId64 ".", OffsetPtr);
+
+
+ PreReadOffset = OffsetPtr;
+ auto Filename = Reader.getFixedLengthString(&OffsetPtr, NameLen);
+ if (OffsetPtr == PreReadOffset)
+ return createStringError(
+ std::make_error_code(std::errc::executable_format_error),
+ "Failed reading symbol %" PRId64 ".", OffsetPtr);
+ Filenames.emplace_back(std::string(Filename));
+
+ llvm::outs() << "Read filename: " << Filename << "\n";
+
+ // Skip to start of next 32 byte record. Subtract 8 to main to account
+ // for 8 byte advance after switch.
+ auto BytesUsedInChunk = (OffsetPtr - FilenameBeginOffset + 2) % 32;
+ auto BytesToSkip =
+ BytesUsedInChunk > 0 ? 32 - BytesUsedInChunk % 32 : 0;
+ OffsetPtr += BytesToSkip - 8;
+ break;
+ }
default:
return createStringError(
std::make_error_code(std::errc::executable_format_error),
@@ -443,8 +586,9 @@ Expected<Trace> llvm::xray::loadTrace(const DataExtractor &DE, bool Sort) {
switch (Type) {
case NAIVE_FORMAT:
if (Version == 1 || Version == 2 || Version == 3) {
+ llvm::outs() << "Version is " << Version << "\n";
if (auto E = loadNaiveFormatLog(DE.getData(), DE.isLittleEndian(),
- T.FileHeader, T.Records))
+ T.FileHeader, T.Records, T.FuncMetadata))
return std::move(E);
} else {
return make_error<StringError>(
diff --git a/llvm/tools/llvm-xray/func-id-helper.cpp b/llvm/tools/llvm-xray/func-id-helper.cpp
index ce4eafd071ecc..469aeec7304e1 100644
--- a/llvm/tools/llvm-xray/func-id-helper.cpp
+++ b/llvm/tools/llvm-xray/func-id-helper.cpp
@@ -23,6 +23,12 @@ std::string FuncIdConversionHelper::SymbolOrNumber(int32_t FuncId) const {
if (CacheIt != CachedNames.end())
return CacheIt->second;
+ auto* lookupRes = LookupFn(FuncId);
+ if (lookupRes) {
+ CachedNames[FuncId] = lookupRes->Name;
+ return lookupRes->Name;
+ }
+
std::ostringstream F;
auto It = FunctionAddresses.find(FuncId);
if (It == FunctionAddresses.end()) {
@@ -52,25 +58,38 @@ std::string FuncIdConversionHelper::SymbolOrNumber(int32_t FuncId) const {
}
std::string FuncIdConversionHelper::FileLineAndColumn(int32_t FuncId) const {
- auto It = FunctionAddresses.find(FuncId);
- if (It == FunctionAddresses.end())
- return "(unknown)";
- std::ostringstream F;
- object::SectionedAddress ModuleAddress;
- ModuleAddress.Address = It->second;
- // TODO: set proper section index here.
- // object::SectionedAddress::UndefSection works for only absolute addresses.
- ModuleAddress.SectionIndex = object::SectionedAddress::UndefSection;
- auto ResOrErr = Symbolizer.symbolizeCode(BinaryInstrMap, ModuleAddress);
- if (!ResOrErr) {
- consumeError(ResOrErr.takeError());
- return "(unknown)";
- }
+ std::string Filename;
+ int Line;
+ int Column;
- auto &DI = *ResOrErr;
- F << sys::path::filename(DI.FileName).str() << ":" << DI.Line << ":"
- << DI.Column;
+ auto *LookupRes = LookupFn(FuncId);
+ if (LookupRes) {
+ Filename = LookupRes->File;
+ Line = LookupRes->Line;
+ Column = 0;
+ } else {
+ auto It = FunctionAddresses.find(FuncId);
+ if (It == FunctionAddresses.end())
+ return "(unknown)";
+ object::SectionedAddress ModuleAddress;
+ ModuleAddress.Address = It->second;
+ // TODO: set proper section index here.
+ // object::SectionedAddress::UndefSection works for only absolute addresses.
+ ModuleAddress.SectionIndex = object::SectionedAddress::UndefSection;
+ auto ResOrErr = Symbolizer.symbolizeCode(BinaryInstrMap, ModuleAddress);
+ if (!ResOrErr) {
+ consumeError(ResOrErr.takeError());
+ return "(unknown)";
+ }
+ auto &DI = *ResOrErr;
+ Filename = DI.FileName;
+ Line = DI.Line;
+ Column = DI.Column;
+ }
+ std::ostringstream F;
+ F << sys::path::filename(Filename).str() << ":" << Line << ":"
+ << Column;
return F.str();
}
diff --git a/llvm/tools/llvm-xray/func-id-helper.h b/llvm/tools/llvm-xray/func-id-helper.h
index d99fb7c1cfb0c..aedecf481b46a 100644
--- a/llvm/tools/llvm-xray/func-id-helper.h
+++ b/llvm/tools/llvm-xray/func-id-helper.h
@@ -15,6 +15,7 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/DebugInfo/Symbolize/SymbolizableModule.h"
#include "llvm/DebugInfo/Symbolize/Symbolize.h"
+#include "llvm/XRay/XRayRecord.h"
#include <unordered_map>
namespace llvm {
@@ -24,19 +25,32 @@ namespace xray {
class FuncIdConversionHelper {
public:
using FunctionAddressMap = std::unordered_map<int32_t, uint64_t>;
+ using LookupFnType = std::function<const XRayFunctionInfo*(int32_t FuncId)>;
private:
std::string BinaryInstrMap;
symbolize::LLVMSymbolizer &Symbolizer;
const FunctionAddressMap &FunctionAddresses;
+ LookupFnType LookupFn;
mutable llvm::DenseMap<int32_t, std::string> CachedNames;
public:
FuncIdConversionHelper(std::string BinaryInstrMap,
symbolize::LLVMSymbolizer &Symbolizer,
- const FunctionAddressMap &FunctionAddresses)
+ const FunctionAddressMap &FunctionAddresses,
+
+ LookupFnType LookupFn)
: BinaryInstrMap(std::move(BinaryInstrMap)), Symbolizer(Symbolizer),
- FunctionAddresses(FunctionAddresses) {}
+ FunctionAddresses(FunctionAddresses), LookupFn(std::move(LookupFn)) {}
+
+ FuncIdConversionHelper(std::string BinaryInstrMap,
+ symbolize::LLVMSymbolizer &Symbolizer,
+ const FunctionAddressMap &FunctionAddresses)
+ : FuncIdConversionHelper(std::move(BinaryInstrMap), Symbolizer,
+ FunctionAddresses,
+ [](int32_t FuncId) -> const XRayFunctionInfo* {
+ return nullptr;
+ }) {}
// Returns the symbol or a string representation of the function id.
std::string SymbolOrNumber(int32_t FuncId) const;
diff --git a/llvm/tools/llvm-xray/xray-account.cpp b/llvm/tools/llvm-xray/xray-account.cpp
index 24a3552cfb91e..ce3df581c61fb 100644
--- a/llvm/tools/llvm-xray/xray-account.cpp
+++ b/llvm/tools/llvm-xray/xray-account.cpp
@@ -466,12 +466,6 @@ static CommandRegistration Unused(&Account, []() -> Error {
return make_error<StringError>(
Twine("Cannot open file '") + AccountOutput + "' for writing.", EC);
- const auto &FunctionAddresses = Map.getFunctionAddresses();
- symbolize::LLVMSymbolizer Symbolizer;
- llvm::xray::FuncIdConversionHelper FuncIdHelper(AccountInstrMap, Symbolizer,
- FunctionAddresses);
- xray::LatencyAccountant FCA(FuncIdHelper, AccountRecursiveCallsOnly,
- AccountDeduceSiblingCalls);
auto TraceOrErr = loadTraceFile(AccountInput);
if (!TraceOrErr)
return joinErrors(
@@ -481,6 +475,28 @@ static CommandRegistration Unused(&Account, []() -> Error {
TraceOrErr.takeError());
auto &T = *TraceOrErr;
+
+ auto &FMD = T.getFunctionMetadata();
+
+ std::for_each(FMD.mapping_begin(), FMD.mappping_end(), [](const auto& Mapping) {
+ outs() << "Function MD: " << Mapping.FuncId << " -> " << Mapping.Name << ", file=" << Mapping.File << "\n";
+ });
+
+ const auto &FunctionAddresses = Map.getFunctionAddresses();
+ symbolize::LLVMSymbolizer Symbolizer;
+ llvm::xray::FuncIdConversionHelper FuncIdHelper(AccountInstrMap, Symbolizer,
+ FunctionAddresses, [&FMD](int32_t FuncId) -> const XRayFunctionInfo* {
+ auto It = std::find_if(FMD.mapping_begin(), FMD.mappping_end(), [FuncId](const auto&FInfo) {return FInfo.FuncId == FuncId;});
+ if (It == FMD.mappping_end()) {
+ return nullptr;
+ }
+ return &*It;
+ });
+
+ xray::LatencyAccountant FCA(FuncIdHelper, AccountRecursiveCallsOnly,
+ AccountDeduceSiblingCalls);
+
+
for (const auto &Record : T) {
if (FCA.accountRecord(Record))
continue;
diff --git a/llvm/tools/llvm-xray/xray-account.h b/llvm/tools/llvm-xray/xray-account.h
index 0f24f93b9fd10..4634dbfc14713 100644
--- a/llvm/tools/llvm-xray/xray-account.h
+++ b/llvm/tools/llvm-xray/xray-account.h
@@ -19,7 +19,7 @@
#include "llvm/ADT/Bitfields.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/XRay/XRayRecord.h"
+#include "llvm/XRay/Trace.h"
namespace llvm {
namespace xray {
>From ad95aa1cd68749ea45c48b2ca37b4100215c7032 Mon Sep 17 00:00:00 2001
From: Sebastian Kreutzer <SebastianKreutzer at gmx.net>
Date: Tue, 19 Nov 2024 18:14:52 +0100
Subject: [PATCH 3/5] [XRay][WIP] Fix bugs, remove debug output
---
.../sanitizer_symbolizer_libcdep.cpp | 13 +------
.../sanitizer_symbolizer_posix_libcdep.cpp | 15 ++------
compiler-rt/lib/xray/xray_basic_logging.cpp | 38 ++++++++++---------
compiler-rt/lib/xray/xray_interface.cpp | 6 +--
.../xray/TestCases/Posix/basic-mode-dso.cpp | 9 +----
llvm/lib/XRay/Trace.cpp | 23 ++++++-----
llvm/tools/llvm-xray/xray-account.cpp | 6 +--
7 files changed, 40 insertions(+), 70 deletions(-)
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cpp
index fe83be81fa9a0..74458028ae8f5 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cpp
@@ -111,18 +111,12 @@ bool Symbolizer::SymbolizeData(uptr addr, DataInfo *info) {
info->module = internal_strdup(module_name);
info->module_offset = module_offset;
info->module_arch = arch;
-
- Report("Trying out %d tools\n", tools_.size());
for (auto &tool : tools_) {
SymbolizerScope sym_scope(this);
if (tool.SymbolizeData(addr, info)) {
- Report("Symbolize tool produced data: function %s from module %s in %s:%s\n", info->name, info->module, info->file, info->line);
- //return true;
- } else {
- Report("Tool failed\n");
+ return true;
}
}
- return true; // FIXME Debugging
return false;
}
@@ -441,8 +435,6 @@ bool LLVMSymbolizer::SymbolizeData(uptr addr, DataInfo *info) {
"DATA", info->module, info->module_offset, info->module_arch);
if (!buf)
return false;
- // FIXME: Remove debug output
- Report("Response: %s\n", buf);
ParseSymbolizeDataOutput(buf, info);
info->start += (addr - info->module_offset); // Add the base address.
return true;
@@ -477,9 +469,6 @@ const char *LLVMSymbolizer::FormatAndSendCommand(const char *command_prefix,
return nullptr;
}
- // FIXME: Remove
- Report("Command: %s\n", buffer_);
-
return symbolizer_process_->SendCommand(buffer_);
}
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp
index 69e372e89cecc..0ddc24802d216 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp
@@ -341,16 +341,10 @@ __sanitizer_symbolize_set_inline_frames(bool InlineFrames);
class InternalSymbolizer final : public SymbolizerTool {
public:
static InternalSymbolizer *get(LowLevelAllocator *alloc) {
- if (&__sanitizer_symbolize_code == nullptr) {
- VReport(2, "interal symbolizer not linked!\n");
- }
// These one is the most used one, so we will use it to detect a presence of
// internal symbolizer.
- if (&__sanitizer_symbolize_code == nullptr) {
+ if (&__sanitizer_symbolize_code == nullptr)
return nullptr;
- }
-
-
CHECK(__sanitizer_symbolize_set_demangle(common_flags()->demangle));
CHECK(__sanitizer_symbolize_set_inline_frames(
common_flags()->symbolize_inline_frames));
@@ -471,7 +465,6 @@ static SymbolizerTool *ChooseExternalSymbolizer(LowLevelAllocator *allocator) {
static void ChooseSymbolizerTools(IntrusiveList<SymbolizerTool> *list,
LowLevelAllocator *allocator) {
- VReport(2, "Choosing symbolizer\n");
if (!common_flags()->symbolize) {
VReport(2, "Symbolizer is disabled.\n");
return;
@@ -487,14 +480,12 @@ static void ChooseSymbolizerTools(IntrusiveList<SymbolizerTool> *list,
} else if (SymbolizerTool *tool = InternalSymbolizer::get(allocator)) {
VReport(2, "Using internal symbolizer.\n");
list->push_back(tool);
-// return;
- } else {
- VReport(2, "Cannot instantiate internal symbolizer!\n");
+ return;
}
if (SymbolizerTool *tool = LibbacktraceSymbolizer::get(allocator)) {
VReport(2, "Using libbacktrace symbolizer.\n");
list->push_back(tool);
-// return;
+ return;
}
if (SymbolizerTool *tool = ChooseExternalSymbolizer(allocator)) {
diff --git a/compiler-rt/lib/xray/xray_basic_logging.cpp b/compiler-rt/lib/xray/xray_basic_logging.cpp
index 9ba310db3de07..1847372fbf6f4 100644
--- a/compiler-rt/lib/xray/xray_basic_logging.cpp
+++ b/compiler-rt/lib/xray/xray_basic_logging.cpp
@@ -214,22 +214,25 @@ struct FunctionRecordBuffer {
AddressInfo& AI = MDI.second;
int FileMDIdx = 0;
-
- // TODO: Does this work with strings?
- if (auto *It = FileMDMap.find(StringKey(AI.file)); It) {
- FileMDIdx = It->second;
- } else {
- XRayFileMD FMD;
- FMD.FilenameLen = static_cast<int16_t>(internal_strlen(AI.file));
- Writer->WriteAll(reinterpret_cast<char *>(&FMD),
- reinterpret_cast<char *>(&FMD.FilenameBuffer));
- Writer->WriteAll(AI.file, AI.file + FMD.FilenameLen);
- constexpr int FilenameBufferSize = sizeof(FMD.FilenameBuffer);
- auto NumPaddingBytes = FMD.FilenameLen < FilenameBufferSize ? FilenameBufferSize - FMD.FilenameLen : 32 - (FMD.FilenameLen - FilenameBufferSize) % 32;
- Writer->WritePadding(NumPaddingBytes);
- FileMDMap[AI.file] = FileMDCount;
- FileMDIdx = FileMDCount;
- FileMDCount++;
+ if (AI.file) {
+ if (auto *It = FileMDMap.find(StringKey(AI.file)); It) {
+ FileMDIdx = It->second;
+ } else {
+ XRayFileMD FMD;
+ FMD.FilenameLen = static_cast<int16_t>(internal_strlen(AI.file));
+ Writer->WriteAll(reinterpret_cast<char *>(&FMD),
+ reinterpret_cast<char *>(&FMD.FilenameBuffer));
+ Writer->WriteAll(AI.file, AI.file + FMD.FilenameLen);
+ constexpr int FilenameBufferSize = sizeof(FMD.FilenameBuffer);
+ auto NumPaddingBytes =
+ FMD.FilenameLen < FilenameBufferSize
+ ? FilenameBufferSize - FMD.FilenameLen
+ : 32 - (FMD.FilenameLen - FilenameBufferSize) % 32;
+ Writer->WritePadding(NumPaddingBytes);
+ FileMDCount++;
+ FileMDMap[AI.file] = FileMDCount;
+ FileMDIdx = FileMDCount;
+ }
}
XRayFunctionMD FIR;
@@ -243,8 +246,7 @@ struct FunctionRecordBuffer {
Writer->WriteAll(AI.function, AI.function + FIR.NameLen);
constexpr int NameBufferSize = sizeof(FIR.NameBuffer);
auto NumPaddingBytes = FIR.NameLen < NameBufferSize ? NameBufferSize - FIR.NameLen : 32 - (FIR.NameLen - NameBufferSize) % 32;
- Report("Writing string %s (length %d) for ID %d, adding padding bytes: %d\n",
- AI.function, FIR.NameLen, FIR.FuncId, NumPaddingBytes);
+
Writer->WritePadding(NumPaddingBytes);
// auto ObjId = UnpackId(Id).first;
diff --git a/compiler-rt/lib/xray/xray_interface.cpp b/compiler-rt/lib/xray/xray_interface.cpp
index 275390ad09d05..7605c22a03717 100644
--- a/compiler-rt/lib/xray/xray_interface.cpp
+++ b/compiler-rt/lib/xray/xray_interface.cpp
@@ -528,11 +528,7 @@ bool Symbolize(int32_t PackedId, AddressInfo* AI) {
return false;
}
- printf("Adding Entry: %d -> %x\n", PackedId, Addr);
-// printf("Symbol Info: function %s from module %s in %s:%s\n", DI->name, DI->module, DI->file, DI->line);
-
-
- printf("Symbol Info (stack): function %s from module %s in %s:%d\n", SymStack->info.function, SymStack->info.module, SymStack->info.file, SymStack->info.line);
+// printf("Symbol Info: function %s from module %s in %s:%d\n", SymStack->info.function, SymStack->info.module, SymStack->info.file, SymStack->info.line);
// XRay does not support inlined function instrumentation.
// Therefor we only look at the first function stack entry.
diff --git a/compiler-rt/test/xray/TestCases/Posix/basic-mode-dso.cpp b/compiler-rt/test/xray/TestCases/Posix/basic-mode-dso.cpp
index acabe03b51eb4..ddb4792350330 100644
--- a/compiler-rt/test/xray/TestCases/Posix/basic-mode-dso.cpp
+++ b/compiler-rt/test/xray/TestCases/Posix/basic-mode-dso.cpp
@@ -4,9 +4,9 @@
// RUN: %clangxx_xray -g -fPIC -fxray-instrument -fxray-shared -shared -std=c++11 %t/testlib.cpp -o %t/testlib.so
// RUN: %clangxx_xray -g -fPIC -fxray-instrument -fxray-shared -std=c++11 %t/main.cpp %t/testlib.so -Wl,-rpath,%t -o %t/main.o
+// RUN: rm -f basic-mode-dso-*
// RUN: XRAY_OPTIONS="patch_premain=false,xray_mode=xray-basic,xray_logfile_base=basic-mode-dso-,verbosity=1" XRAY_BASIC_OPTIONS="func_duration_threshold_us=0" %run %t/main.o 2>&1 | FileCheck %s
// RUN: %llvm_xray account --format=csv --sort=funcid "`ls basic-mode-dso-* | head -1`" | FileCheck --check-prefix=ACCOUNT %s
-// RUN: rm basic-mode-dso-*
// REQUIRES: target={{(aarch64|x86_64)-.*}}
// REQUIRES: built-in-llvm-tree
@@ -39,17 +39,10 @@ int main() {
#include <cstdio>
#include <unistd.h>
-[[clang::xray_always_instrument]] void instrumented_in_dso2() {
- printf("instrumented_in_dso2 called\n");
-}
-
-
[[clang::xray_always_instrument]] void instrumented_in_dso() {
printf("instrumented_in_dso called\n");
- instrumented_in_dso2();
}
-
// ACCOUNT: funcid,count,min,median,90%ile,99%ile,max,sum,debug,function
// ACCOUNT-NEXT: 1,1,{{.*}}
// ACCOUNT-NEXT: 16777217,1,{{.*}}
diff --git a/llvm/lib/XRay/Trace.cpp b/llvm/lib/XRay/Trace.cpp
index bcb7d5460bf82..3c8ffc8d99662 100644
--- a/llvm/lib/XRay/Trace.cpp
+++ b/llvm/lib/XRay/Trace.cpp
@@ -231,14 +231,18 @@ Error loadNaiveFormatLog(StringRef Data, bool IsLittleEndian,
std::make_error_code(std::errc::executable_format_error),
"Failed reading file metadata field at offset %" PRId64 ".",
OffsetPtr);
- if (FileMDIdx < 0 || static_cast<size_t>(FileMDIdx) >= Filenames.size()) {
- return createStringError(
- std::make_error_code(std::errc::executable_format_error),
- "File metadata does not exist at offset %" PRId64 ".",
- OffsetPtr);
+ if (FileMDIdx == 0) {
+ // 0 means unavailable
+ Info.File = "(unknown)";
+ } else {
+ if (FileMDIdx < 1 ||
+ static_cast<size_t>(FileMDIdx-1) >= Filenames.size()) {
+ return createStringError(
+ std::make_error_code(std::errc::executable_format_error),
+ "File metadata does not exist at offset %" PRId64 ".", OffsetPtr);
+ }
+ Info.File = Filenames[FileMDIdx-1];
}
- outs() << "MD index is: " << FileMDIdx << "\n";
- Info.File = Filenames[FileMDIdx];
PreReadOffset = OffsetPtr;
auto NameLen = Reader.getU16(&OffsetPtr);
@@ -258,8 +262,6 @@ Error loadNaiveFormatLog(StringRef Data, bool IsLittleEndian,
FuncMetadata.AddFunctionInfo(Info);
- llvm::outs() << "Read function: " << FuncId << ": " << FName << "\n";
-
// Skip to start of next 32 byte record. Subtract 8 to main to account
// for 8 byte advance after switch.
auto BytesUsedInChunk = (OffsetPtr - FInfoBeginOffset + 2) % 32;
@@ -331,8 +333,6 @@ Error loadNaiveFormatLog(StringRef Data, bool IsLittleEndian,
"Failed reading symbol %" PRId64 ".", OffsetPtr);
Filenames.emplace_back(std::string(Filename));
- llvm::outs() << "Read filename: " << Filename << "\n";
-
// Skip to start of next 32 byte record. Subtract 8 to main to account
// for 8 byte advance after switch.
auto BytesUsedInChunk = (OffsetPtr - FilenameBeginOffset + 2) % 32;
@@ -586,7 +586,6 @@ Expected<Trace> llvm::xray::loadTrace(const DataExtractor &DE, bool Sort) {
switch (Type) {
case NAIVE_FORMAT:
if (Version == 1 || Version == 2 || Version == 3) {
- llvm::outs() << "Version is " << Version << "\n";
if (auto E = loadNaiveFormatLog(DE.getData(), DE.isLittleEndian(),
T.FileHeader, T.Records, T.FuncMetadata))
return std::move(E);
diff --git a/llvm/tools/llvm-xray/xray-account.cpp b/llvm/tools/llvm-xray/xray-account.cpp
index ce3df581c61fb..effff719ebbcd 100644
--- a/llvm/tools/llvm-xray/xray-account.cpp
+++ b/llvm/tools/llvm-xray/xray-account.cpp
@@ -478,9 +478,9 @@ static CommandRegistration Unused(&Account, []() -> Error {
auto &FMD = T.getFunctionMetadata();
- std::for_each(FMD.mapping_begin(), FMD.mappping_end(), [](const auto& Mapping) {
- outs() << "Function MD: " << Mapping.FuncId << " -> " << Mapping.Name << ", file=" << Mapping.File << "\n";
- });
+// std::for_each(FMD.mapping_begin(), FMD.mappping_end(), [](const auto& Mapping) {
+// outs() << "Function MD: " << Mapping.FuncId << " -> " << Mapping.Name << ", file=" << Mapping.File << "\n";
+// });
const auto &FunctionAddresses = Map.getFunctionAddresses();
symbolize::LLVMSymbolizer Symbolizer;
>From b68e8045be791ad99feebaf362a5ef9981d610c5 Mon Sep 17 00:00:00 2001
From: Sebastian Kreutzer <SebastianKreutzer at gmx.net>
Date: Tue, 19 Nov 2024 18:51:09 +0100
Subject: [PATCH 4/5] [XRay][WIP] Thread safety in symbolize function
---
compiler-rt/lib/xray/xray_interface.cpp | 18 +++++++++++++-----
1 file changed, 13 insertions(+), 5 deletions(-)
diff --git a/compiler-rt/lib/xray/xray_interface.cpp b/compiler-rt/lib/xray/xray_interface.cpp
index 7605c22a03717..80eb23127ee79 100644
--- a/compiler-rt/lib/xray/xray_interface.cpp
+++ b/compiler-rt/lib/xray/xray_interface.cpp
@@ -512,13 +512,21 @@ bool Symbolize(int32_t PackedId, AddressInfo* AI) {
auto Ids = UnpackId(PackedId);
auto ObjId = Ids.first;
auto FuncId = Ids.second;
- auto& SledMap = XRayInstrMaps[ObjId];
- // TODO: Thread safety
+ XRaySledMap InstrMap;
+ {
+ SpinMutexLock Guard(&XRayInstrMapMutex);
+ if (ObjId < 0 || static_cast<uint32_t>(ObjId) >=
+ atomic_load(&XRayNumObjects, memory_order_acquire)) {
+ Report("Unable to patch function: invalid sled map index: %d\n", ObjId);
+ return false;
+ }
+ InstrMap = XRayInstrMaps[ObjId];
+ }
const XRaySledEntry *Sled =
- SledMap.SledsIndex ? SledMap.SledsIndex[FuncId - 1].fromPCRelative()
- : findFunctionSleds(FuncId, SledMap).Begin;
+ InstrMap.SledsIndex ? InstrMap.SledsIndex[FuncId - 1].fromPCRelative()
+ : findFunctionSleds(FuncId, InstrMap).Begin;
auto Addr = Sled->function();
Symbolizer* Sym = Symbolizer::GetOrInit();
@@ -664,7 +672,7 @@ int __xray_symbolize(int32_t PackedId, XRaySymbolInfo* SymInfo) {
SymInfo->File = ai.file;
SymInfo->Line = ai.line;
- // TODO: DataInfo owns its memory, so passing char pointers is okay for now.
+ // TODO: AddressInfo owns its memory, so passing char pointers is okay for now.
// Need to free at some point.
return true;
>From 82bb16ee5094cd7759bcf579eaf56f3b32a19f88 Mon Sep 17 00:00:00 2001
From: Sebastian Kreutzer <SebastianKreutzer at gmx.net>
Date: Tue, 21 Jan 2025 15:39:01 +0100
Subject: [PATCH 5/5] [XRay] Refactoring and cleanup
---
compiler-rt/include/xray/xray_interface.h | 5 +-
compiler-rt/lib/xray/xray_interface.cpp | 50 +------------------
...ort-function-map.cpp => symbolize-dso.cpp} | 15 +++---
3 files changed, 10 insertions(+), 60 deletions(-)
rename compiler-rt/test/xray/TestCases/Posix/{export-function-map.cpp => symbolize-dso.cpp} (83%)
diff --git a/compiler-rt/include/xray/xray_interface.h b/compiler-rt/include/xray/xray_interface.h
index 9e6ebd6cf33f3..e3ac316102ccb 100644
--- a/compiler-rt/include/xray/xray_interface.h
+++ b/compiler-rt/include/xray/xray_interface.h
@@ -34,10 +34,7 @@ struct XRaySymbolInfo {
int64_t Line;
};
-extern int __xray_symbolize(int32_t PackedId, XRaySymbolInfo* SymInfo);
-
-//extern FunctionMapEntry* __xray_export_function_map();
-
+extern int __xray_symbolize(int32_t, XRaySymbolInfo*);
/// Synchronize this with AsmPrinter::SledKind in LLVM.
enum XRayEntryType {
diff --git a/compiler-rt/lib/xray/xray_interface.cpp b/compiler-rt/lib/xray/xray_interface.cpp
index 80eb23127ee79..554fccd2b7512 100644
--- a/compiler-rt/lib/xray/xray_interface.cpp
+++ b/compiler-rt/lib/xray/xray_interface.cpp
@@ -539,7 +539,7 @@ bool Symbolize(int32_t PackedId, AddressInfo* AI) {
// printf("Symbol Info: function %s from module %s in %s:%d\n", SymStack->info.function, SymStack->info.module, SymStack->info.file, SymStack->info.line);
// XRay does not support inlined function instrumentation.
- // Therefor we only look at the first function stack entry.
+ // Therefore, we only look at the first function stack entry.
*AI = SymStack->info;
return true;
@@ -607,54 +607,6 @@ uint16_t __xray_register_event_type(
return h->type_id;
}
-//FunctionMapEntry* __xray_export_function_map() {
-// if (!atomic_load(&XRayInitialized, memory_order_acquire))
-// return {};
-//
-// SpinMutexLock Guard(&XRayInstrMapMutex);
-//
-// // No atomic load necessary since we have acquired the mutex
-// uint32_t NumObjects = atomic_load(&XRayNumObjects, memory_order_acquire);
-//
-// FunctionMapEntry* FMap = new FunctionMapEntry;
-// FMap->Next = nullptr;
-//
-// Symbolizer* Sym = Symbolizer::GetOrInit();
-// Sym->RefreshModules();
-//
-//
-// printf("Objects: %d\n", NumObjects);
-//
-//
-// FunctionMapEntry* LastEntry = FMap;
-// for (int Obj = 0; Obj < NumObjects; Obj++) {
-// auto& SledMap = XRayInstrMaps[Obj];
-// printf("Functions (%d): %d\n", Obj, SledMap.Functions);
-// for (int F = 1; F <= SledMap.Functions; F++) {
-// const XRaySledEntry *Sled =
-// SledMap.SledsIndex ? SledMap.SledsIndex[F - 1].fromPCRelative()
-// : findFunctionSleds(F, SledMap).Begin;
-// auto Addr = Sled->function();
-// auto PackedId = __xray_pack_id(F, Obj);
-//
-//
-// DataInfo DI;
-// Sym->SymbolizeData(Addr, &DI);
-//
-// printf("Adding Entry: %d -> %x\n", PackedId, Addr);
-// printf("Symbol Info: function %s from module %s in %s:%s\n", DI.name, DI.module, DI.file, DI.line);
-//
-// LastEntry->FunctionId = PackedId;
-// LastEntry->Addr = Addr;
-// LastEntry->Next = new FunctionMapEntry;
-// LastEntry = LastEntry->Next;
-// LastEntry->Next = nullptr;
-// }
-// }
-//
-// return FMap;
-//}
-
int __xray_symbolize(int32_t PackedId, XRaySymbolInfo* SymInfo) {
if (!SymInfo) {
return 0; // TODO Error msg?
diff --git a/compiler-rt/test/xray/TestCases/Posix/export-function-map.cpp b/compiler-rt/test/xray/TestCases/Posix/symbolize-dso.cpp
similarity index 83%
rename from compiler-rt/test/xray/TestCases/Posix/export-function-map.cpp
rename to compiler-rt/test/xray/TestCases/Posix/symbolize-dso.cpp
index c2706d43ee777..50104fd23628c 100644
--- a/compiler-rt/test/xray/TestCases/Posix/export-function-map.cpp
+++ b/compiler-rt/test/xray/TestCases/Posix/symbolize-dso.cpp
@@ -1,4 +1,4 @@
-// Check that we can export the global function map.
+// Check that we can symbolize functions
//
// RUN: split-file %s %t
@@ -15,11 +15,13 @@
#include <cstdio>
-bool called = false;
-
void test_handler(int32_t fid, XRayEntryType type) {
printf("called: %d, type=%d\n", fid, static_cast<int32_t>(type));
- called = true;
+ XRaySymbolInfo SymInfo;
+ int status = __xray_symbolize(fid, &SymInfo);
+ if (!status)
+ return;
+ printf("function name: %s\n", SymInfo.function);
}
[[clang::xray_always_instrument]] void instrumented_in_executable() {
@@ -37,16 +39,15 @@ int main() {
// CHECK-NEXT: called: {{.*}}, type=0
// CHECK-NEXT: instrumented_in_executable called
// CHECK-NEXT: called: {{.*}}, type=1
+ // CHECK-NEXT: function name: instrumented_in_executable
instrumented_in_dso();
// CHECK-NEXT: called: {{.*}}, type=0
// CHECK-NEXT: instrumented_in_dso called
// CHECK-NEXT: called: {{.*}}, type=1
+ // CHECK-NEXT: function name: instrumented_in_dso
status = __xray_unpatch();
printf("patching status: %d\n", static_cast<int32_t>(status));
// CHECK-NEXT: patching status: 1
- // FIXME
-// auto map = __xray_export_function_map();
-// printf("Entry: %d -> %x\n", map->FunctionId, map->Addr);
}
//--- testlib.cpp
More information about the llvm-commits
mailing list