Skip to content

Commit c146c3b

Browse files
author
Andres Villegas
authored
[sanitizer_symbolizer] RenderContextual elements for symbolizer markup.
This is part of a stack of PRs to add support for symbolizer markup in linux. Render contextual symbolizer markup elements. For Fuchsia it is not necessary to emit any context given that Fuchsia's logging infrastructure already handles emitting it when necessary. For more information about contextual symbolizer markup elements: https://llvm.org/docs/SymbolizerMarkupFormat.html#contextual-elements Reviewers: PiJoules, petrhosek, vitalybuka Reviewed By: petrhosek, vitalybuka Pull Request: #73194
1 parent d24d7ed commit c146c3b

File tree

7 files changed

+160
-1
lines changed

7 files changed

+160
-1
lines changed

compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,8 @@ class Symbolizer final {
154154

155155
void InvalidateModuleList();
156156

157+
const ListOfModules &GetRefreshedListOfModules();
158+
157159
private:
158160
// GetModuleNameAndOffsetForPC has to return a string to the caller.
159161
// Since the corresponding module might get unloaded later, we should create

compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,13 @@ void Symbolizer::RefreshModules() {
191191
modules_fresh_ = true;
192192
}
193193

194+
const ListOfModules &Symbolizer::GetRefreshedListOfModules() {
195+
if (!modules_fresh_)
196+
RefreshModules();
197+
198+
return modules_;
199+
}
200+
194201
static const LoadedModule *SearchForModule(const ListOfModules &modules,
195202
uptr address) {
196203
for (uptr i = 0; i < modules.size(); i++) {

compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup.cpp

Lines changed: 94 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
#include "sanitizer_symbolizer_markup.h"
2020

2121
#include "sanitizer_common.h"
22-
#include "sanitizer_stacktrace_printer.h"
2322
#include "sanitizer_symbolizer.h"
2423
#include "sanitizer_symbolizer_markup_constants.h"
2524

@@ -28,6 +27,7 @@ namespace __sanitizer {
2827
void MarkupStackTracePrinter::RenderData(InternalScopedString *buffer,
2928
const char *format, const DataInfo *DI,
3029
const char *strip_path_prefix) {
30+
RenderContext(buffer);
3131
buffer->AppendF(kFormatData, DI->start);
3232
}
3333

@@ -42,6 +42,7 @@ void MarkupStackTracePrinter::RenderFrame(InternalScopedString *buffer,
4242
bool vs_style,
4343
const char *strip_path_prefix) {
4444
CHECK(!RenderNeedsSymbolization(format));
45+
RenderContext(buffer);
4546
buffer->AppendF(kFormatFrame, frame_no, address);
4647
}
4748

@@ -64,4 +65,96 @@ const char *MarkupSymbolizerTool::Demangle(const char *name) {
6465
return buffer;
6566
}
6667

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+
67160
} // namespace __sanitizer

compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@
2020

2121
namespace __sanitizer {
2222

23+
// Simplier view of a LoadedModule. It only holds information necessary to
24+
// identify unique modules.
25+
struct RenderedModule {
26+
char *full_name;
27+
uptr base_address;
28+
u8 uuid[kModuleUUIDSize]; // BuildId
29+
};
30+
2331
class MarkupStackTracePrinter : public StackTracePrinter {
2432
public:
2533
// We don't support the stack_trace_format flag at all.
@@ -35,6 +43,9 @@ class MarkupStackTracePrinter : public StackTracePrinter {
3543
const char *strip_path_prefix = "") override;
3644

3745
private:
46+
// Keeps track of the modules that have been rendered to avoid re-rendering
47+
// them
48+
InternalMmapVector<RenderedModule> renderedModules_;
3849
void RenderContext(InternalScopedString *buffer);
3950

4051
protected:

compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup_constants.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,12 @@ constexpr const char *kFormatData = "{{{data:%p}}}";
3535
// One frame in a backtrace (printed on a line by itself).
3636
constexpr const char *kFormatFrame = "{{{bt:%u:%p}}}";
3737

38+
// Module contextual element.
39+
constexpr const char *kFormatModule = "{{{module:%d:%s:elf:%s}}}";
40+
41+
// mmap for a module segment.
42+
constexpr const char *kFormatMmap = "{{{mmap:%p:0x%x:load:%d:%s:0x%x}}}";
43+
3844
// Dump trigger element.
3945
#define FORMAT_DUMPFILE "{{{dumpfile:%s:%s}}}"
4046

compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup_fuchsia.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ StackTracePrinter *StackTracePrinter::NewStackTracePrinter() {
7272
return new (GetGlobalLowLevelAllocator()) MarkupStackTracePrinter();
7373
}
7474

75+
void MarkupStackTracePrinter::RenderContext(InternalScopedString *) {}
76+
7577
Symbolizer *Symbolizer::PlatformInit() {
7678
return new (symbolizer_allocator_) Symbolizer({});
7779
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// RUN: %clangxx %s -o %t
2+
// RUN: %env_tool_opts=enable_symbolizer_markup=1 %run %t 2>&1 | FileCheck %s
3+
4+
// REQUIRES: linux
5+
#include <sanitizer/common_interface_defs.h>
6+
7+
void Bar() { __sanitizer_print_stack_trace(); }
8+
9+
void Foo() {
10+
Bar();
11+
return;
12+
}
13+
14+
void Baz() { __sanitizer_print_stack_trace(); }
15+
16+
int main() {
17+
Foo();
18+
Baz();
19+
return 0;
20+
}
21+
22+
// COM: For element syntax see: https://llvm.org/docs/SymbolizerMarkupFormat.html
23+
// COM: OPEN is {{{ and CLOSE is }}}
24+
25+
// CHECK: [[OPEN:{{{]]reset[[CLOSE:}}}]]
26+
// CHECK: [[OPEN]]module:[[MOD_ID:[0-9]+]]:{{.+}}:elf:{{[0-9a-fA-F]+}}[[CLOSE]]
27+
// CHECK: [[OPEN]]mmap:{{0x[0-9a-fA-F]+:0x[0-9a-fA-F]+}}:load:[[MOD_ID]]:{{r[wx]{0,2}:0x[0-9a-fA-F]+}}[[CLOSE]]
28+
// CHECK: [[OPEN]]bt:0:0x{{[0-9a-fA-F]+}}[[CLOSE]]
29+
// CHECK-NEXT: [[OPEN]]bt:1:0x{{[0-9a-fA-F]+}}[[CLOSE]]
30+
// CHECK-NEXT: [[OPEN]]bt:2:0x{{[0-9a-fA-F]+}}[[CLOSE]]
31+
32+
// COM: Emitting a second backtrace should not emit contextual elements in this case.
33+
// CHECK-NOT: [[OPEN:{{{]]reset[[CLOSE:}}}]]
34+
// CHECK-NOT: [[OPEN]]module:[[MOD_ID:[0-9]+]]:{{.+}}:elf:{{[0-9a-fA-F]+}}[[CLOSE]]
35+
// CHECK-NOT: [[OPEN]]mmap:{{0x[0-9a-fA-F]+:0x[0-9a-fA-F]+}}:load:[[MOD_ID]]:{{r[wx]{0,2}:0x[0-9a-fA-F]+}}[[CLOSE]]
36+
37+
// CHECK: [[OPEN]]bt:0:0x{{[0-9a-fA-F]+}}[[CLOSE]]
38+
// CHECK-NEXT: [[OPEN]]bt:1:0x{{[0-9a-fA-F]+}}[[CLOSE]]

0 commit comments

Comments
 (0)