aboutsummaryrefslogtreecommitdiff
path: root/compiler-rt
diff options
context:
space:
mode:
authorAndres Villegas <andresvi@google.com>2023-12-04 10:28:41 -0800
committerGitHub <noreply@github.com>2023-12-04 10:28:41 -0800
commitc146c3b7471af576103971354f0d4c7b78f11495 (patch)
tree83b8f2686c90be9f075d324fc69974dbed4cbf7d /compiler-rt
parentd24d7edaef9517edd9eb2ab26b02969e201bbcad (diff)
downloadllvm-c146c3b7471af576103971354f0d4c7b78f11495.zip
llvm-c146c3b7471af576103971354f0d4c7b78f11495.tar.gz
llvm-c146c3b7471af576103971354f0d4c7b78f11495.tar.bz2
[sanitizer_symbolizer] RenderContextual elements for symbolizer markup.
This is part of a stack of PRs to add support for symbolizer markup in linux. Render contextual symbolizer markup elements. For Fuchsia it is not necessary to emit any context given that Fuchsia's logging infrastructure already handles emitting it when necessary. For more information about contextual symbolizer markup elements: https://llvm.org/docs/SymbolizerMarkupFormat.html#contextual-elements Reviewers: PiJoules, petrhosek, vitalybuka Reviewed By: petrhosek, vitalybuka Pull Request: https://github.com/llvm/llvm-project/pull/73194
Diffstat (limited to 'compiler-rt')
-rw-r--r--compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.h2
-rw-r--r--compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cpp7
-rw-r--r--compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup.cpp95
-rw-r--r--compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup.h11
-rw-r--r--compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup_constants.h6
-rw-r--r--compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup_fuchsia.cpp2
-rw-r--r--compiler-rt/test/sanitizer_common/TestCases/print-stack-trace-markup.cpp38
7 files changed, 160 insertions, 1 deletions
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.h b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.h
index 7fb7928..82cd9bc 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.h
@@ -154,6 +154,8 @@ class Symbolizer final {
void InvalidateModuleList();
+ const ListOfModules &GetRefreshedListOfModules();
+
private:
// GetModuleNameAndOffsetForPC has to return a string to the caller.
// Since the corresponding module might get unloaded later, we should create
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cpp
index 8114102..7445802 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cpp
@@ -191,6 +191,13 @@ void Symbolizer::RefreshModules() {
modules_fresh_ = true;
}
+const ListOfModules &Symbolizer::GetRefreshedListOfModules() {
+ if (!modules_fresh_)
+ RefreshModules();
+
+ return modules_;
+}
+
static const LoadedModule *SearchForModule(const ListOfModules &modules,
uptr address) {
for (uptr i = 0; i < modules.size(); i++) {
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup.cpp
index 1627908..b2a1069 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup.cpp
@@ -19,7 +19,6 @@
#include "sanitizer_symbolizer_markup.h"
#include "sanitizer_common.h"
-#include "sanitizer_stacktrace_printer.h"
#include "sanitizer_symbolizer.h"
#include "sanitizer_symbolizer_markup_constants.h"
@@ -28,6 +27,7 @@ namespace __sanitizer {
void MarkupStackTracePrinter::RenderData(InternalScopedString *buffer,
const char *format, const DataInfo *DI,
const char *strip_path_prefix) {
+ RenderContext(buffer);
buffer->AppendF(kFormatData, DI->start);
}
@@ -42,6 +42,7 @@ void MarkupStackTracePrinter::RenderFrame(InternalScopedString *buffer,
bool vs_style,
const char *strip_path_prefix) {
CHECK(!RenderNeedsSymbolization(format));
+ RenderContext(buffer);
buffer->AppendF(kFormatFrame, frame_no, address);
}
@@ -64,4 +65,96 @@ const char *MarkupSymbolizerTool::Demangle(const char *name) {
return buffer;
}
+// Fuchsia's implementation of symbolizer markup doesn't need to emit contextual
+// elements at this point.
+// Fuchsia's logging infrastructure emits enough information about
+// process memory layout that a post-processing filter can do the
+// symbolization and pretty-print the markup.
+#if !SANITIZER_FUCHSIA
+
+static bool ModulesEq(const LoadedModule &module,
+ const RenderedModule &renderedModule) {
+ return module.base_address() == renderedModule.base_address &&
+ internal_memcmp(module.uuid(), renderedModule.uuid,
+ module.uuid_size()) == 0 &&
+ internal_strcmp(module.full_name(), renderedModule.full_name) == 0;
+}
+
+static bool ModuleHasBeenRendered(
+ const LoadedModule &module,
+ const InternalMmapVectorNoCtor<RenderedModule> &renderedModules) {
+ for (const auto &renderedModule : renderedModules)
+ if (ModulesEq(module, renderedModule))
+ return true;
+
+ return false;
+}
+
+static void RenderModule(InternalScopedString *buffer,
+ const LoadedModule &module, uptr moduleId) {
+ InternalScopedString buildIdBuffer;
+ for (uptr i = 0; i < module.uuid_size(); i++)
+ buildIdBuffer.AppendF("%02x", module.uuid()[i]);
+
+ buffer->AppendF(kFormatModule, moduleId, module.full_name(),
+ buildIdBuffer.data());
+ buffer->Append("\n");
+}
+
+static void RenderMmaps(InternalScopedString *buffer,
+ const LoadedModule &module, uptr moduleId) {
+ InternalScopedString accessBuffer;
+
+ // All module mmaps are readable at least
+ for (const auto &range : module.ranges()) {
+ accessBuffer.Append("r");
+ if (range.writable)
+ accessBuffer.Append("w");
+ if (range.executable)
+ accessBuffer.Append("x");
+
+ //{{{mmap:%starting_addr:%size_in_hex:load:%moduleId:r%(w|x):%relative_addr}}}
+
+ // module.base_address == dlpi_addr
+ // range.beg == dlpi_addr + p_vaddr
+ // relative address == p_vaddr == range.beg - module.base_address
+ buffer->AppendF(kFormatMmap, range.beg, range.end - range.beg, moduleId,
+ accessBuffer.data(), range.beg - module.base_address());
+
+ buffer->Append("\n");
+ accessBuffer.clear();
+ }
+}
+
+void MarkupStackTracePrinter::RenderContext(InternalScopedString *buffer) {
+ if (renderedModules_.size() == 0)
+ buffer->Append("{{{reset}}}\n");
+
+ const auto &modules = Symbolizer::GetOrInit()->GetRefreshedListOfModules();
+
+ for (const auto &module : modules) {
+ if (ModuleHasBeenRendered(module, renderedModules_))
+ continue;
+
+ // symbolizer markup id, used to refer to this modules from other contextual
+ // elements
+ uptr moduleId = renderedModules_.size();
+
+ RenderModule(buffer, module, moduleId);
+ RenderMmaps(buffer, module, moduleId);
+
+ renderedModules_.push_back({
+ internal_strdup(module.full_name()),
+ module.base_address(),
+ {},
+ });
+
+ // kModuleUUIDSize is the size of curModule.uuid
+ CHECK_GE(kModuleUUIDSize, module.uuid_size());
+ internal_memcpy(renderedModules_.back().uuid, module.uuid(),
+ module.uuid_size());
+ }
+}
+#endif // !SANITIZER_FUCHSIA
+
} // namespace __sanitizer
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup.h b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup.h
index 07630d0..bc2ab24 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup.h
@@ -20,6 +20,14 @@
namespace __sanitizer {
+// Simplier view of a LoadedModule. It only holds information necessary to
+// identify unique modules.
+struct RenderedModule {
+ char *full_name;
+ uptr base_address;
+ u8 uuid[kModuleUUIDSize]; // BuildId
+};
+
class MarkupStackTracePrinter : public StackTracePrinter {
public:
// We don't support the stack_trace_format flag at all.
@@ -35,6 +43,9 @@ class MarkupStackTracePrinter : public StackTracePrinter {
const char *strip_path_prefix = "") override;
private:
+ // Keeps track of the modules that have been rendered to avoid re-rendering
+ // them
+ InternalMmapVector<RenderedModule> renderedModules_;
void RenderContext(InternalScopedString *buffer);
protected:
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup_constants.h b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup_constants.h
index 0f96ca7..8364350 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup_constants.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup_constants.h
@@ -35,6 +35,12 @@ constexpr const char *kFormatData = "{{{data:%p}}}";
// One frame in a backtrace (printed on a line by itself).
constexpr const char *kFormatFrame = "{{{bt:%u:%p}}}";
+// Module contextual element.
+constexpr const char *kFormatModule = "{{{module:%d:%s:elf:%s}}}";
+
+// mmap for a module segment.
+constexpr const char *kFormatMmap = "{{{mmap:%p:0x%x:load:%d:%s:0x%x}}}";
+
// Dump trigger element.
#define FORMAT_DUMPFILE "{{{dumpfile:%s:%s}}}"
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup_fuchsia.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup_fuchsia.cpp
index f6c49aa..08b06c2 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup_fuchsia.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup_fuchsia.cpp
@@ -72,6 +72,8 @@ StackTracePrinter *StackTracePrinter::NewStackTracePrinter() {
return new (GetGlobalLowLevelAllocator()) MarkupStackTracePrinter();
}
+void MarkupStackTracePrinter::RenderContext(InternalScopedString *) {}
+
Symbolizer *Symbolizer::PlatformInit() {
return new (symbolizer_allocator_) Symbolizer({});
}
diff --git a/compiler-rt/test/sanitizer_common/TestCases/print-stack-trace-markup.cpp b/compiler-rt/test/sanitizer_common/TestCases/print-stack-trace-markup.cpp
new file mode 100644
index 0000000..15d89d0
--- /dev/null
+++ b/compiler-rt/test/sanitizer_common/TestCases/print-stack-trace-markup.cpp
@@ -0,0 +1,38 @@
+// RUN: %clangxx %s -o %t
+// RUN: %env_tool_opts=enable_symbolizer_markup=1 %run %t 2>&1 | FileCheck %s
+
+// REQUIRES: linux
+#include <sanitizer/common_interface_defs.h>
+
+void Bar() { __sanitizer_print_stack_trace(); }
+
+void Foo() {
+ Bar();
+ return;
+}
+
+void Baz() { __sanitizer_print_stack_trace(); }
+
+int main() {
+ Foo();
+ Baz();
+ return 0;
+}
+
+// COM: For element syntax see: https://llvm.org/docs/SymbolizerMarkupFormat.html
+// COM: OPEN is {{{ and CLOSE is }}}
+
+// CHECK: [[OPEN:{{{]]reset[[CLOSE:}}}]]
+// CHECK: [[OPEN]]module:[[MOD_ID:[0-9]+]]:{{.+}}:elf:{{[0-9a-fA-F]+}}[[CLOSE]]
+// CHECK: [[OPEN]]mmap:{{0x[0-9a-fA-F]+:0x[0-9a-fA-F]+}}:load:[[MOD_ID]]:{{r[wx]{0,2}:0x[0-9a-fA-F]+}}[[CLOSE]]
+// CHECK: [[OPEN]]bt:0:0x{{[0-9a-fA-F]+}}[[CLOSE]]
+// CHECK-NEXT: [[OPEN]]bt:1:0x{{[0-9a-fA-F]+}}[[CLOSE]]
+// CHECK-NEXT: [[OPEN]]bt:2:0x{{[0-9a-fA-F]+}}[[CLOSE]]
+
+// COM: Emitting a second backtrace should not emit contextual elements in this case.
+// CHECK-NOT: [[OPEN:{{{]]reset[[CLOSE:}}}]]
+// CHECK-NOT: [[OPEN]]module:[[MOD_ID:[0-9]+]]:{{.+}}:elf:{{[0-9a-fA-F]+}}[[CLOSE]]
+// CHECK-NOT: [[OPEN]]mmap:{{0x[0-9a-fA-F]+:0x[0-9a-fA-F]+}}:load:[[MOD_ID]]:{{r[wx]{0,2}:0x[0-9a-fA-F]+}}[[CLOSE]]
+
+// CHECK: [[OPEN]]bt:0:0x{{[0-9a-fA-F]+}}[[CLOSE]]
+// CHECK-NEXT: [[OPEN]]bt:1:0x{{[0-9a-fA-F]+}}[[CLOSE]]