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 25 namespace __sanitizer { 26 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)); 32 } 33 34 bool MarkupStackTracePrinter::RenderNeedsSymbolization(const char *format) { 35 return false; 36 } 37 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, 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 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); 54 return true; 55 } 56 57 bool MarkupSymbolizerTool::SymbolizeData(uptr addr, DataInfo *info) { 58 info->Clear(); 59 info->start = addr; 60 return true; 61 } 62 63 const 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 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; 82 } 83 84 static 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 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]); 99 100 buffer->AppendF(kFormatModule, moduleId, module.full_name(), 101 buildIdBuffer.data()); 102 buffer->Append("\n"); 103 } 104 105 static 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 131 void 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 163