master
  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(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 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
 75
 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 least
110  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_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());
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 contextual
142    // elements
143    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.uuid
155    CHECK_GE(kModuleUUIDSize, module.uuid_size());
156    internal_memcpy(renderedModules_.back().uuid, module.uuid(),
157                    module.uuid_size());
158  }
159}
160#endif  // !SANITIZER_FUCHSIA
161
162}  // namespace __sanitizer