1 //===-- sanitizer_symbolizer_markup.cpp -----------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file is shared between various sanitizers' runtime libraries.
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.
16 // https://llvm.org/docs/SymbolizerMarkupFormat.html
17 //===----------------------------------------------------------------------===//
19 #include "sanitizer_symbolizer_markup.h"
21 #include "sanitizer_common.h"
22 #include "sanitizer_symbolizer.h"
23 #include "sanitizer_symbolizer_markup_constants.h"
25 namespace __sanitizer
{
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
));
34 bool MarkupStackTracePrinter::RenderNeedsSymbolization(const char *format
) {
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
,
43 const char *strip_path_prefix
) {
44 CHECK(!RenderNeedsSymbolization(format
));
45 RenderContext(buffer
);
46 buffer
->AppendF(kFormatFrame
, frame_no
, reinterpret_cast<void *>(address
));
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
);
57 bool MarkupSymbolizerTool::SymbolizeData(uptr addr
, DataInfo
*info
) {
63 const char *MarkupSymbolizerTool::Demangle(const char *name
) {
64 static char buffer
[kFormatDemangleMax
];
65 internal_snprintf(buffer
, sizeof(buffer
), kFormatDemangle
, name
);
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
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;
84 static bool ModuleHasBeenRendered(
85 const LoadedModule
&module
,
86 const InternalMmapVectorNoCtor
<RenderedModule
> &renderedModules
) {
87 for (const auto &renderedModule
: renderedModules
)
88 if (ModulesEq(module
, renderedModule
))
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
]);
100 buffer
->AppendF(kFormatModule
, moduleId
, module
.full_name(),
101 buildIdBuffer
.data());
102 buffer
->Append("\n");
105 static void RenderMmaps(InternalScopedString
*buffer
,
106 const LoadedModule
&module
, uptr moduleId
) {
107 InternalScopedString accessBuffer
;
109 // All module mmaps are readable at least
110 for (const auto &range
: module
.ranges()) {
111 accessBuffer
.Append("r");
113 accessBuffer
.Append("w");
114 if (range
.executable
)
115 accessBuffer
.Append("x");
117 //{{{mmap:%starting_addr:%size_in_hex:load:%moduleId:r%(w|x):%relative_addr}}}
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());
126 buffer
->Append("\n");
127 accessBuffer
.clear();
131 void MarkupStackTracePrinter::RenderContext(InternalScopedString
*buffer
) {
132 if (renderedModules_
.size() == 0)
133 buffer
->Append("{{{reset}}}\n");
135 const auto &modules
= Symbolizer::GetOrInit()->GetRefreshedListOfModules();
137 for (const auto &module
: modules
) {
138 if (ModuleHasBeenRendered(module
, renderedModules_
))
141 // symbolizer markup id, used to refer to this modules from other contextual
143 uptr moduleId
= renderedModules_
.size();
145 RenderModule(buffer
, module
, moduleId
);
146 RenderMmaps(buffer
, module
, moduleId
);
148 renderedModules_
.push_back({
149 internal_strdup(module
.full_name()),
150 module
.base_address(),
154 // kModuleUUIDSize is the size of curModule.uuid
155 CHECK_GE(kModuleUUIDSize
, module
.uuid_size());
156 internal_memcpy(renderedModules_
.back().uuid
, module
.uuid(),
160 #endif // !SANITIZER_FUCHSIA
162 } // namespace __sanitizer