[compiler-rt] c146c3b - [sanitizer_symbolizer] RenderContextual elements for symbolizer markup.

via llvm-commits llvm-commits at lists.llvm.org
Mon Dec 4 10:28:45 PST 2023


Author: Andres Villegas
Date: 2023-12-04T10:28:41-08:00
New Revision: c146c3b7471af576103971354f0d4c7b78f11495

URL: https://github.com/llvm/llvm-project/commit/c146c3b7471af576103971354f0d4c7b78f11495
DIFF: https://github.com/llvm/llvm-project/commit/c146c3b7471af576103971354f0d4c7b78f11495.diff

LOG: [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

Added: 
    compiler-rt/test/sanitizer_common/TestCases/print-stack-trace-markup.cpp

Modified: 
    compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.h
    compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cpp
    compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup.cpp
    compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup.h
    compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup_constants.h
    compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup_fuchsia.cpp

Removed: 
    


################################################################################
diff  --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.h b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.h
index 7fb7928dce0d8..82cd9bc227916 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 81141023386ea..74458028ae8f5 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 1627908185f20..b2a1069a9a61c 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 07630d0b3bdf4..bc2ab24d625bb 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 0f96ca78600a5..83643504e1289 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 f6c49aa59d7b5..08b06c2faf30d 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 0000000000000..15d89d091a99e
--- /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]]


        


More information about the llvm-commits mailing list