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