163 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// This file is shared between various sanitizers' runtime libraries.10//11// This generic support for offline symbolizing is based on the12// Fuchsia port. We don't do any actual symbolization per se.13// Instead, we emit text containing raw addresses and raw linkage14// symbol names, embedded in Fuchsia's symbolization markup format.15// See the spec at:16// https://llvm.org/docs/SymbolizerMarkupFormat.html17//===----------------------------------------------------------------------===//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(kFormatData, reinterpret_cast<void *>(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(kFormatFrame, frame_no, reinterpret_cast<void *>(address));47}48 49bool 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 57bool MarkupSymbolizerTool::SymbolizeData(uptr addr, DataInfo *info) {58 info->Clear();59 info->start = addr;60 return true;61}62 63const 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 contextual70// elements at this point.71// Fuchsia's logging infrastructure emits enough information about72// process memory layout that a post-processing filter can do the73// symbolization and pretty-print the markup.74#if !SANITIZER_FUCHSIA75 76static 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 84static 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 94static 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 105static void RenderMmaps(InternalScopedString *buffer,106 const LoadedModule &module, uptr moduleId) {107 InternalScopedString accessBuffer;108 109 // All module mmaps are readable at least110 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_addr120 // range.beg == dlpi_addr + p_vaddr121 // relative address == p_vaddr == range.beg - module.base_address122 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 131void 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 contextual142 // elements143 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.uuid155 CHECK_GE(kModuleUUIDSize, module.uuid_size());156 internal_memcpy(renderedModules_.back().uuid, module.uuid(),157 module.uuid_size());158 }159}160#endif // !SANITIZER_FUCHSIA161 162} // namespace __sanitizer163