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
25namespace __sanitizer {
26
27void MarkupStackTracePrinter::RenderData(InternalScopedString *buffer,
28 const char *format, const DataInfo *DI,
29 const char *strip_path_prefix) {
30 RenderContext(buffer);
31 buffer->AppendF(format: kFormatData, DI->start);
32}
33
34bool MarkupStackTracePrinter::RenderNeedsSymbolization(const char *format) {
35 return false;
36}
37
38// We don't support the stack_trace_format flag at all.
39void 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(format: kFormatFrame, frame_no, address);
47}
48
49bool MarkupSymbolizerTool::SymbolizePC(uptr addr, SymbolizedStack *stack) {
50 char buffer[kFormatFunctionMax];
51 internal_snprintf(buffer, length: sizeof(buffer), format: kFormatFunction, addr);
52 stack->info.function = internal_strdup(s: buffer);
53 return true;
54}
55
56bool MarkupSymbolizerTool::SymbolizeData(uptr addr, DataInfo *info) {
57 info->Clear();
58 info->start = addr;
59 return true;
60}
61
62const char *MarkupSymbolizerTool::Demangle(const char *name) {
63 static char buffer[kFormatDemangleMax];
64 internal_snprintf(buffer, length: sizeof(buffer), format: 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
75static bool ModulesEq(const LoadedModule &module,
76 const RenderedModule &renderedModule) {
77 return module.base_address() == renderedModule.base_address &&
78 internal_memcmp(s1: module.uuid(), s2: renderedModule.uuid,
79 n: module.uuid_size()) == 0 &&
80 internal_strcmp(s1: module.full_name(), s2: renderedModule.full_name) == 0;
81}
82
83static 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
93static 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(format: "%02x", module.uuid()[i]);
98
99 buffer->AppendF(format: kFormatModule, moduleId, module.full_name(),
100 buildIdBuffer.data());
101 buffer->Append(str: "\n");
102}
103
104static 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(str: "r");
111 if (range.writable)
112 accessBuffer.Append(str: "w");
113 if (range.executable)
114 accessBuffer.Append(str: "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(format: kFormatMmap, range.beg, range.end - range.beg, moduleId,
122 accessBuffer.data(), range.beg - module.base_address());
123
124 buffer->Append(str: "\n");
125 accessBuffer.clear();
126 }
127}
128
129void MarkupStackTracePrinter::RenderContext(InternalScopedString *buffer) {
130 if (renderedModules_.size() == 0)
131 buffer->Append(str: "{{{reset}}}\n");
132
133 const auto &modules = Symbolizer::GetOrInit()->GetRefreshedListOfModules();
134
135 for (const auto &module : modules) {
136 if (ModuleHasBeenRendered(module, renderedModules: 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(element: {
147 .full_name: internal_strdup(s: module.full_name()),
148 .base_address: module.base_address(),
149 .uuid: {},
150 });
151
152 // kModuleUUIDSize is the size of curModule.uuid
153 CHECK_GE(kModuleUUIDSize, module.uuid_size());
154 internal_memcpy(dest: renderedModules_.back().uuid, src: module.uuid(),
155 n: module.uuid_size());
156 }
157}
158#endif // !SANITIZER_FUCHSIA
159
160} // namespace __sanitizer
161

source code of compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup.cpp