Skip to content

Commit

Permalink
[饾榾饾椊饾椏] initial version
Browse files Browse the repository at this point in the history
Created using spr 1.3.4
  • Loading branch information
avillega committed Nov 23, 2023
2 parents b14f651 + 462a4ce commit b8bec1b
Show file tree
Hide file tree
Showing 11 changed files with 359 additions and 72 deletions.
2 changes: 2 additions & 0 deletions compiler-rt/lib/sanitizer_common/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ set(SANITIZER_SYMBOLIZER_SOURCES
sanitizer_symbolizer_libcdep.cpp
sanitizer_symbolizer_mac.cpp
sanitizer_symbolizer_markup.cpp
sanitizer_symbolizer_markup_fuchsia.cpp
sanitizer_symbolizer_posix_libcdep.cpp
sanitizer_symbolizer_report.cpp
sanitizer_symbolizer_report_fuchsia.cpp
Expand Down Expand Up @@ -195,6 +196,7 @@ set(SANITIZER_IMPL_HEADERS
sanitizer_symbolizer_internal.h
sanitizer_symbolizer_libbacktrace.h
sanitizer_symbolizer_mac.h
sanitizer_symbolizer_markup.h
sanitizer_syscall_generic.inc
sanitizer_syscall_linux_aarch64.inc
sanitizer_syscall_linux_arm.inc
Expand Down
4 changes: 4 additions & 0 deletions compiler-rt/lib/sanitizer_common/sanitizer_flags.inc
Original file line number Diff line number Diff line change
Expand Up @@ -275,3 +275,7 @@ COMMON_FLAG(bool, test_only_emulate_no_memorymap, false,
// program.
COMMON_FLAG(bool, test_only_replace_dlopen_main_program, false,
"TEST ONLY replace dlopen(<main program>,...) with dlopen(NULL)")

COMMON_FLAG(bool, enable_symbolizer_markup, SANITIZER_FUCHSIA,
"Use sanitizer symbolizer markup, available on Linux "
"and always set true for fuchsia.")
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "sanitizer_file.h"
#include "sanitizer_flags.h"
#include "sanitizer_fuchsia.h"
#include "sanitizer_symbolizer_markup.h"

namespace __sanitizer {

Expand Down Expand Up @@ -62,6 +63,9 @@ const char *StackTracePrinter::StripFunctionName(const char *function) {
#if !SANITIZER_SYMBOLIZER_MARKUP

StackTracePrinter *StackTracePrinter::NewStackTracePrinter() {
if (common_flags()->enable_symbolizer_markup)
return new (GetGlobalLowLevelAllocator()) MarkupStackTracePrinter();

return new (GetGlobalLowLevelAllocator()) FormattedStackTracePrinter();
}

Expand Down
2 changes: 2 additions & 0 deletions compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.h
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,8 @@ class Symbolizer final {

void InvalidateModuleList();

const ListOfModules &GetRefreshedListOfModules();

private:
// GetModuleNameAndOffsetForPC has to return a string to the caller.
// Since the corresponding module might get unloaded later, we should create
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,13 @@ void Symbolizer::RefreshModules() {
modules_fresh_ = true;
}

const ListOfModules &Symbolizer::GetRefreshedListOfModules() {
if (!modules_fresh_)
RefreshModules();

return modules_;
}

static const LoadedModule *SearchForModule(const ListOfModules &modules,
uptr address) {
for (uptr i = 0; i < modules.size(); i++) {
Expand Down
208 changes: 136 additions & 72 deletions compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,105 +8,169 @@
//
// This file is shared between various sanitizers' runtime libraries.
//
// Implementation of offline markup symbolizer.
// This generic support for offline symbolizing is based on the
// Fuchsia port. We don't do any actual symbolization per se.
// Instead, we emit text containing raw addresses and raw linkage
// symbol names, embedded in Fuchsia's symbolization markup format.
// See the spec at:
// https://llvm.org/docs/SymbolizerMarkupFormat.html
//===----------------------------------------------------------------------===//

#include "sanitizer_platform.h"
#include "sanitizer_symbolizer_markup.h"

#if SANITIZER_SYMBOLIZER_MARKUP

# include "sanitizer_common.h"
# include "sanitizer_stacktrace_printer.h"
# include "sanitizer_symbolizer.h"
# include "sanitizer_symbolizer_markup_constants.h"
#include "sanitizer_common.h"
#include "sanitizer_stacktrace_printer.h"
#include "sanitizer_symbolizer.h"
#include "sanitizer_symbolizer_markup_constants.h"

namespace __sanitizer {

// This generic support for offline symbolizing is based on the
// Fuchsia port. We don't do any actual symbolization per se.
// Instead, we emit text containing raw addresses and raw linkage
// symbol names, embedded in Fuchsia's symbolization markup format.
// Fuchsia's logging infrastructure emits enough information about
// process memory layout that a post-processing filter can do the
// symbolization and pretty-print the markup. See the spec at:
// https://fuchsia.googlesource.com/zircon/+/master/docs/symbolizer_markup.md

// This is used by UBSan for type names, and by ASan for global variable names.
// It's expected to return a static buffer that will be reused on each call.
const char *Symbolizer::Demangle(const char *name) {
static char buffer[kFormatDemangleMax];
internal_snprintf(buffer, sizeof(buffer), kFormatDemangle, name);
return buffer;
void MarkupStackTracePrinter::RenderData(InternalScopedString *buffer,
const char *format, const DataInfo *DI,
const char *strip_path_prefix) {
RenderContext(buffer);
buffer->AppendF(kFormatData, DI->start);
}

// This is used mostly for suppression matching. Making it work
// would enable "interceptor_via_lib" suppressions. It's also used
// once in UBSan to say "in module ..." in a message that also
// includes an address in the module, so post-processing can already
// pretty-print that so as to indicate the module.
bool Symbolizer::GetModuleNameAndOffsetForPC(uptr pc, const char **module_name,
uptr *module_address) {
bool MarkupStackTracePrinter::RenderNeedsSymbolization(const char *format) {
return false;
}

// This is mainly used by hwasan for online symbolization. This isn't needed
// since hwasan can always just dump stack frames for offline symbolization.
bool Symbolizer::SymbolizeFrame(uptr addr, FrameInfo *info) { return false; }

// This is used in some places for suppression checking, which we
// don't really support for Fuchsia. It's also used in UBSan to
// identify a PC location to a function name, so we always fill in
// the function member with a string containing markup around the PC
// value.
// TODO(mcgrathr): Under SANITIZER_GO, it's currently used by TSan
// to render stack frames, but that should be changed to use
// RenderStackFrame.
SymbolizedStack *Symbolizer::SymbolizePC(uptr addr) {
SymbolizedStack *s = SymbolizedStack::New(addr);
// We don't support the stack_trace_format flag at all.
void MarkupStackTracePrinter::RenderFrame(InternalScopedString *buffer,
const char *format, int frame_no,
uptr address, const AddressInfo *info,
bool vs_style,
const char *strip_path_prefix) {
CHECK(!RenderNeedsSymbolization(format));
RenderContext(buffer);
buffer->AppendF(kFormatFrame, frame_no, address);
}

bool MarkupSymbolizerTool::SymbolizePC(uptr addr, SymbolizedStack *stack) {
char buffer[kFormatFunctionMax];
internal_snprintf(buffer, sizeof(buffer), kFormatFunction, addr);
s->info.function = internal_strdup(buffer);
return s;
stack->info.function = internal_strdup(buffer);
return true;
}

// Always claim we succeeded, so that RenderDataInfo will be called.
bool Symbolizer::SymbolizeData(uptr addr, DataInfo *info) {
bool MarkupSymbolizerTool::SymbolizeData(uptr addr, DataInfo *info) {
info->Clear();
info->start = addr;
return true;
}

class MarkupStackTracePrinter : public StackTracePrinter {
// We ignore the format argument to __sanitizer_symbolize_global.
void RenderData(InternalScopedString *buffer, const char *format,
const DataInfo *DI, const char *strip_path_prefix) override {
buffer->AppendF(kFormatData, DI->start);
}
const char *MarkupSymbolizerTool::Demangle(const char *name) {
static char buffer[kFormatDemangleMax];
internal_snprintf(buffer, sizeof(buffer), kFormatDemangle, name);
return buffer;
}

bool RenderNeedsSymbolization(const char *format) override { return false; }
// Fuchsia's implementation of symbolizer markup doesn't need to emit contextual
// elements at this point.
// Fuchsia's logging infrastructure emits enough information about
// process memory layout that a post-processing filter can do the
// symbolization and pretty-print the markup.
#if !SANITIZER_FUCHSIA

// Simplier view of a LoadedModule. It only holds information necessary to
// identify unique modules.
struct RenderedModule {
char *full_name;
uptr base_address;
u8 uuid[kModuleUUIDSize]; // BuildId
};

// We don't support the stack_trace_format flag at all.
void RenderFrame(InternalScopedString *buffer, const char *format,
int frame_no, uptr address, const AddressInfo *info,
bool vs_style, const char *strip_path_prefix) override {
CHECK(!RenderNeedsSymbolization(format));
buffer->AppendF(kFormatFrame, frame_no, address);
}
static bool ModulesEq(const LoadedModule &module,
const RenderedModule &renderedModule) {
return module.base_address() == renderedModule.base_address &&
internal_memcmp(module.uuid(), renderedModule.uuid,
module.uuid_size()) == 0 &&
internal_strcmp(module.full_name(), renderedModule.full_name) == 0;
}

protected:
~MarkupStackTracePrinter();
};
static bool ModuleHasBeenRendered(
const LoadedModule &module,
const InternalMmapVectorNoCtor<RenderedModule> &renderedModules) {
for (const auto &renderedModule : renderedModules)
if (ModulesEq(module, renderedModule))
return true;

StackTracePrinter *StackTracePrinter::NewStackTracePrinter() {
return new (GetGlobalLowLevelAllocator()) MarkupStackTracePrinter();
return false;
}

Symbolizer *Symbolizer::PlatformInit() {
return new (symbolizer_allocator_) Symbolizer({});
static void RenderModule(InternalScopedString *buffer,
const LoadedModule &module, uptr moduleId) {
InternalScopedString buildIdBuffer;
for (uptr i = 0; i < module.uuid_size(); i++)
buildIdBuffer.AppendF("%02x", module.uuid()[i]);

buffer->AppendF(kFormatModule, moduleId, module.full_name(),
buildIdBuffer.data());
buffer->Append("\n");
}

void Symbolizer::LateInitialize() { Symbolizer::GetOrInit(); }
static void RenderMmaps(InternalScopedString *buffer,
const LoadedModule &module, uptr moduleId) {
InternalScopedString accessBuffer;

} // namespace __sanitizer
// All module mmaps are readable at least
for (const auto &range : module.ranges()) {
accessBuffer.Append("r");
if (range.writable)
accessBuffer.Append("w");
if (range.executable)
accessBuffer.Append("x");

//{{{mmap:%starting_addr:%size_in_hex:load:%moduleId:r%(w|x):%relative_addr}}}

// module.base_address == dlpi_addr
// range.beg == dlpi_addr + p_vaddr
// relative address == p_vaddr == range.beg - module.base_address
buffer->AppendF(kFormatMmap, range.beg, range.end - range.beg, moduleId,
accessBuffer.data(), range.beg - module.base_address());

buffer->Append("\n");
accessBuffer.clear();
}
}

#endif // SANITIZER_SYMBOLIZER_MARKUP
void MarkupStackTracePrinter::RenderContext(InternalScopedString *buffer) {
// Keeps track of the modules that have been rendered.
static bool initialized = false;
static InternalMmapVectorNoCtor<RenderedModule> renderedModules;
if (!initialized) {
// arbitrary initial size, counting the main module plus some important libs
// like libc.
renderedModules.Initialize(3);
initialized = true;
}

if (renderedModules.size() == 0)
buffer->Append("{{{reset}}}\n");

const auto &modules = Symbolizer::GetOrInit()->GetRefreshedListOfModules();

for (const auto &module : modules) {
if (ModuleHasBeenRendered(module, renderedModules))
continue;

// symbolizer markup id, used to refer to this modules from other contextual
// elements
uptr moduleId = renderedModules.size();

RenderModule(buffer, module, moduleId);
RenderMmaps(buffer, module, moduleId);

RenderedModule renderedModule{
internal_strdup(module.full_name()), module.base_address(), {}};

// kModuleUUIDSize is the size of curModule.uuid
CHECK_GE(kModuleUUIDSize, module.uuid_size());
internal_memcpy(renderedModule.uuid, module.uuid(), module.uuid_size());
renderedModules.push_back(renderedModule);
}
}
#endif // !SANITIZER_FUCHSIA

} // namespace __sanitizer
68 changes: 68 additions & 0 deletions compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
//===-- sanitizer_symbolizer_markup.h -----------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file is shared between various sanitizers' runtime libraries.
//
// Header for the offline markup symbolizer.
//===----------------------------------------------------------------------===//
#ifndef SANITIZER_SYMBOLIZER_MARKUP_H
#define SANITIZER_SYMBOLIZER_MARKUP_H

#include "sanitizer_common.h"
#include "sanitizer_stacktrace_printer.h"
#include "sanitizer_symbolizer.h"
#include "sanitizer_symbolizer_internal.h"

namespace __sanitizer {

class MarkupStackTracePrinter : public StackTracePrinter {
public:
// We don't support the stack_trace_format flag at all.
void RenderFrame(InternalScopedString *buffer, const char *format,
int frame_no, uptr address, const AddressInfo *info,
bool vs_style, const char *strip_path_prefix = "") override;

bool RenderNeedsSymbolization(const char *format) override;

// We ignore the format argument to __sanitizer_symbolize_global.
void RenderData(InternalScopedString *buffer, const char *format,
const DataInfo *DI,
const char *strip_path_prefix = "") override;

private:
void RenderContext(InternalScopedString *buffer);

protected:
~MarkupStackTracePrinter() {}
};

class MarkupSymbolizerTool final : public SymbolizerTool {
public:
// This is used in some places for suppression checking, which we
// don't really support for Fuchsia. It's also used in UBSan to
// identify a PC location to a function name, so we always fill in
// the function member with a string containing markup around the PC
// value.
// TODO(mcgrathr): Under SANITIZER_GO, it's currently used by TSan
// to render stack frames, but that should be changed to use
// RenderStackFrame.
bool SymbolizePC(uptr addr, SymbolizedStack *stack) override;

// Always claim we succeeded, so that RenderDataInfo will be called.
bool SymbolizeData(uptr addr, DataInfo *info) override;

// May return NULL if demangling failed.
// This is used by UBSan for type names, and by ASan for global variable
// names. It's expected to return a static buffer that will be reused on each
// call.
const char *Demangle(const char *name) override;
};

} // namespace __sanitizer

#endif // SANITIZER_SYMBOLIZER_MARKUP_H
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ constexpr const char *kFormatData = "{{{data:%p}}}";
// One frame in a backtrace (printed on a line by itself).
constexpr const char *kFormatFrame = "{{{bt:%u:%p}}}";

// Module contextual element.
constexpr const char *kFormatModule = "{{{module:%d:%s:elf:%s}}}";

// mmap for a module segment.
constexpr const char *kFormatMmap = "{{{mmap:%p:0x%x:load:%d:%s:0x%x}}}";

// Dump trigger element.
#define FORMAT_DUMPFILE "{{{dumpfile:%s:%s}}}"

Expand Down

0 comments on commit b8bec1b

Please sign in to comment.