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 
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, DI->start);
32 }
33 
34 bool MarkupStackTracePrinter::RenderNeedsSymbolization(const char *format) {
35   return false;
36 }
37 
38 // We don't support the stack_trace_format flag at all.
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, address);
47 }
48 
49 bool MarkupSymbolizerTool::SymbolizePC(uptr addr, SymbolizedStack *stack) {
50   char buffer[kFormatFunctionMax];
51   internal_snprintf(buffer, sizeof(buffer), kFormatFunction, addr);
52   stack->info.function = internal_strdup(buffer);
53   return true;
54 }
55 
56 bool MarkupSymbolizerTool::SymbolizeData(uptr addr, DataInfo *info) {
57   info->Clear();
58   info->start = addr;
59   return true;
60 }
61 
62 const char *MarkupSymbolizerTool::Demangle(const char *name) {
63   static char buffer[kFormatDemangleMax];
64   internal_snprintf(buffer, sizeof(buffer), kFormatDemangle, name);
65   return buffer;
66 }
67 
68 // Fuchsia's implementation of symbolizer markup doesn't need to emit contextual
69 // elements at this point.
70 // Fuchsia's logging infrastructure emits enough information about
71 // process memory layout that a post-processing filter can do the
72 // symbolization and pretty-print the markup.
73 #if !SANITIZER_FUCHSIA
74 
75 static bool ModulesEq(const LoadedModule &module,
76                       const RenderedModule &renderedModule) {
77   return module.base_address() == renderedModule.base_address &&
78          internal_memcmp(module.uuid(), renderedModule.uuid,
79                          module.uuid_size()) == 0 &&
80          internal_strcmp(module.full_name(), renderedModule.full_name) == 0;
81 }
82 
83 static bool ModuleHasBeenRendered(
84     const LoadedModule &module,
85     const InternalMmapVectorNoCtor<RenderedModule> &renderedModules) {
86   for (const auto &renderedModule : renderedModules)
87     if (ModulesEq(module, renderedModule))
88       return true;
89 
90   return false;
91 }
92 
93 static void RenderModule(InternalScopedString *buffer,
94                          const LoadedModule &module, uptr moduleId) {
95   InternalScopedString buildIdBuffer;
96   for (uptr i = 0; i < module.uuid_size(); i++)
97     buildIdBuffer.AppendF("%02x", module.uuid()[i]);
98 
99   buffer->AppendF(kFormatModule, moduleId, module.full_name(),
100                   buildIdBuffer.data());
101   buffer->Append("\n");
102 }
103 
104 static void RenderMmaps(InternalScopedString *buffer,
105                         const LoadedModule &module, uptr moduleId) {
106   InternalScopedString accessBuffer;
107 
108   // All module mmaps are readable at least
109   for (const auto &range : module.ranges()) {
110     accessBuffer.Append("r");
111     if (range.writable)
112       accessBuffer.Append("w");
113     if (range.executable)
114       accessBuffer.Append("x");
115 
116     //{{{mmap:%starting_addr:%size_in_hex:load:%moduleId:r%(w|x):%relative_addr}}}
117 
118     // module.base_address == dlpi_addr
119     // range.beg == dlpi_addr + p_vaddr
120     // relative address == p_vaddr == range.beg - module.base_address
121     buffer->AppendF(kFormatMmap, range.beg, range.end - range.beg, moduleId,
122                     accessBuffer.data(), range.beg - module.base_address());
123 
124     buffer->Append("\n");
125     accessBuffer.clear();
126   }
127 }
128 
129 void MarkupStackTracePrinter::RenderContext(InternalScopedString *buffer) {
130   if (renderedModules_.size() == 0)
131     buffer->Append("{{{reset}}}\n");
132 
133   const auto &modules = Symbolizer::GetOrInit()->GetRefreshedListOfModules();
134 
135   for (const auto &module : modules) {
136     if (ModuleHasBeenRendered(module, renderedModules_))
137       continue;
138 
139     // symbolizer markup id, used to refer to this modules from other contextual
140     // elements
141     uptr moduleId = renderedModules_.size();
142 
143     RenderModule(buffer, module, moduleId);
144     RenderMmaps(buffer, module, moduleId);
145 
146     renderedModules_.push_back({
147         internal_strdup(module.full_name()),
148         module.base_address(),
149         {},
150     });
151 
152     // kModuleUUIDSize is the size of curModule.uuid
153     CHECK_GE(kModuleUUIDSize, module.uuid_size());
154     internal_memcpy(renderedModules_.back().uuid, module.uuid(),
155                     module.uuid_size());
156   }
157 }
158 #endif  // !SANITIZER_FUCHSIA
159 
160 }  // namespace __sanitizer
161