[libc] [libcxx] [compiler-rt] [clang] [clang-tools-extra] [mlir] [flang] [llvm] [sanitizer_symbolizer] RenderContextual elements for symbolizer markup. (PR #73194)

Andres Villegas via cfe-commits cfe-commits at lists.llvm.org
Tue Nov 28 10:44:41 PST 2023


================
@@ -64,4 +66,111 @@ 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
+
+// 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
+};
+
+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) {
+  // Keeps track of the modules that have been rendered.
+  static bool initialized = false;
+  static InternalMmapVectorNoCtor<RenderedModule> renderedModules;
----------------
avillega wrote:

The idea is to keep track of the modules that have been rendered so we don't render them again. On module load modules can be moved around in memory so we have to account for that as well that is why I need a struct to hold on some specific information about a module. When dlopen is called the ListOfModules of the `Symbolzer` gets invalidated and rebuilt, a lot of the time the already loaded modules will not change its location in memory but we can not know that unless we compare the modules we already emitted vs the modules that the `Symbolizer` holds. In my initial implementations the `Render*` functions, these function were free functions and I used static to keep the state in between calls. Now that I've put these functions in a class it makes sense to make the RenderedModules a member of the class instead.

https://github.com/llvm/llvm-project/pull/73194


More information about the cfe-commits mailing list