xref: /freebsd/contrib/llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup.cpp (revision f08bf5a3acf146b17794fbde41279645ddbaa086)
1 //===-- sanitizer_symbolizer_markup.cpp -----------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file is shared between various sanitizers' runtime libraries.
10 //
11 // This generic support for offline symbolizing is based on the
12 // Fuchsia port.  We don't do any actual symbolization per se.
13 // Instead, we emit text containing raw addresses and raw linkage
14 // symbol names, embedded in Fuchsia's symbolization markup format.
15 // See the spec at:
16 // https://llvm.org/docs/SymbolizerMarkupFormat.html
17 //===----------------------------------------------------------------------===//
18 
19 #include "sanitizer_symbolizer_markup.h"
20 
21 #include "sanitizer_common.h"
22 #include "sanitizer_symbolizer.h"
23 #include "sanitizer_symbolizer_markup_constants.h"
24 
25 namespace __sanitizer {
26 
RenderData(InternalScopedString * buffer,const char * format,const DataInfo * DI,const char * strip_path_prefix)27 void MarkupStackTracePrinter::RenderData(InternalScopedString *buffer,
28                                          const char *format, const DataInfo *DI,
29                                          const char *strip_path_prefix) {
30   RenderContext(buffer);
31   buffer->AppendF(kFormatData, reinterpret_cast<void *>(DI->start));
32 }
33 
RenderNeedsSymbolization(const char * format)34 bool MarkupStackTracePrinter::RenderNeedsSymbolization(const char *format) {
35   return false;
36 }
37 
38 // We don't support the stack_trace_format flag at all.
RenderFrame(InternalScopedString * buffer,const char * format,int frame_no,uptr address,const AddressInfo * info,bool vs_style,const char * strip_path_prefix)39 void MarkupStackTracePrinter::RenderFrame(InternalScopedString *buffer,
40                                           const char *format, int frame_no,
41                                           uptr address, const AddressInfo *info,
42                                           bool vs_style,
43                                           const char *strip_path_prefix) {
44   CHECK(!RenderNeedsSymbolization(format));
45   RenderContext(buffer);
46   buffer->AppendF(kFormatFrame, frame_no, reinterpret_cast<void *>(address));
47 }
48 
SymbolizePC(uptr addr,SymbolizedStack * stack)49 bool MarkupSymbolizerTool::SymbolizePC(uptr addr, SymbolizedStack *stack) {
50   char buffer[kFormatFunctionMax];
51   internal_snprintf(buffer, sizeof(buffer), kFormatFunction,
52                     reinterpret_cast<void *>(addr));
53   stack->info.function = internal_strdup(buffer);
54   return true;
55 }
56 
SymbolizeData(uptr addr,DataInfo * info)57 bool MarkupSymbolizerTool::SymbolizeData(uptr addr, DataInfo *info) {
58   info->Clear();
59   info->start = addr;
60   return true;
61 }
62 
Demangle(const char * name)63 const char *MarkupSymbolizerTool::Demangle(const char *name) {
64   static char buffer[kFormatDemangleMax];
65   internal_snprintf(buffer, sizeof(buffer), kFormatDemangle, name);
66   return buffer;
67 }
68 
69 // Fuchsia's implementation of symbolizer markup doesn't need to emit contextual
70 // elements at this point.
71 // Fuchsia's logging infrastructure emits enough information about
72 // process memory layout that a post-processing filter can do the
73 // symbolization and pretty-print the markup.
74 #if !SANITIZER_FUCHSIA
75 
ModulesEq(const LoadedModule & module,const RenderedModule & renderedModule)76 static bool ModulesEq(const LoadedModule &module,
77                       const RenderedModule &renderedModule) {
78   return module.base_address() == renderedModule.base_address &&
79          internal_memcmp(module.uuid(), renderedModule.uuid,
80                          module.uuid_size()) == 0 &&
81          internal_strcmp(module.full_name(), renderedModule.full_name) == 0;
82 }
83 
ModuleHasBeenRendered(const LoadedModule & module,const InternalMmapVectorNoCtor<RenderedModule> & renderedModules)84 static bool ModuleHasBeenRendered(
85     const LoadedModule &module,
86     const InternalMmapVectorNoCtor<RenderedModule> &renderedModules) {
87   for (const auto &renderedModule : renderedModules)
88     if (ModulesEq(module, renderedModule))
89       return true;
90 
91   return false;
92 }
93 
RenderModule(InternalScopedString * buffer,const LoadedModule & module,uptr moduleId)94 static void RenderModule(InternalScopedString *buffer,
95                          const LoadedModule &module, uptr moduleId) {
96   InternalScopedString buildIdBuffer;
97   for (uptr i = 0; i < module.uuid_size(); i++)
98     buildIdBuffer.AppendF("%02x", module.uuid()[i]);
99 
100   buffer->AppendF(kFormatModule, moduleId, module.full_name(),
101                   buildIdBuffer.data());
102   buffer->Append("\n");
103 }
104 
RenderMmaps(InternalScopedString * buffer,const LoadedModule & module,uptr moduleId)105 static void RenderMmaps(InternalScopedString *buffer,
106                         const LoadedModule &module, uptr moduleId) {
107   InternalScopedString accessBuffer;
108 
109   // All module mmaps are readable at least
110   for (const auto &range : module.ranges()) {
111     accessBuffer.Append("r");
112     if (range.writable)
113       accessBuffer.Append("w");
114     if (range.executable)
115       accessBuffer.Append("x");
116 
117     //{{{mmap:%starting_addr:%size_in_hex:load:%moduleId:r%(w|x):%relative_addr}}}
118 
119     // module.base_address == dlpi_addr
120     // range.beg == dlpi_addr + p_vaddr
121     // relative address == p_vaddr == range.beg - module.base_address
122     buffer->AppendF(kFormatMmap, reinterpret_cast<void *>(range.beg),
123                     range.end - range.beg, static_cast<int>(moduleId),
124                     accessBuffer.data(), range.beg - module.base_address());
125 
126     buffer->Append("\n");
127     accessBuffer.clear();
128   }
129 }
130 
RenderContext(InternalScopedString * buffer)131 void MarkupStackTracePrinter::RenderContext(InternalScopedString *buffer) {
132   if (renderedModules_.size() == 0)
133     buffer->Append("{{{reset}}}\n");
134 
135   const auto &modules = Symbolizer::GetOrInit()->GetRefreshedListOfModules();
136 
137   for (const auto &module : modules) {
138     if (ModuleHasBeenRendered(module, renderedModules_))
139       continue;
140 
141     // symbolizer markup id, used to refer to this modules from other contextual
142     // elements
143     uptr moduleId = renderedModules_.size();
144 
145     RenderModule(buffer, module, moduleId);
146     RenderMmaps(buffer, module, moduleId);
147 
148     renderedModules_.push_back({
149         internal_strdup(module.full_name()),
150         module.base_address(),
151         {},
152     });
153 
154     // kModuleUUIDSize is the size of curModule.uuid
155     CHECK_GE(kModuleUUIDSize, module.uuid_size());
156     internal_memcpy(renderedModules_.back().uuid, module.uuid(),
157                     module.uuid_size());
158   }
159 }
160 #endif  // !SANITIZER_FUCHSIA
161 
162 }  // namespace __sanitizer
163