xref: /freebsd/contrib/llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup.cpp (revision f08bf5a3acf146b17794fbde41279645ddbaa086)
168d75effSDimitry Andric //===-- sanitizer_symbolizer_markup.cpp -----------------------------------===//
268d75effSDimitry Andric //
368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
668d75effSDimitry Andric //
768d75effSDimitry Andric //===----------------------------------------------------------------------===//
868d75effSDimitry Andric //
968d75effSDimitry Andric // This file is shared between various sanitizers' runtime libraries.
1068d75effSDimitry Andric //
1168d75effSDimitry Andric // This generic support for offline symbolizing is based on the
1268d75effSDimitry Andric // Fuchsia port.  We don't do any actual symbolization per se.
1368d75effSDimitry Andric // Instead, we emit text containing raw addresses and raw linkage
1468d75effSDimitry Andric // symbol names, embedded in Fuchsia's symbolization markup format.
155f757f3fSDimitry Andric // See the spec at:
165f757f3fSDimitry Andric // https://llvm.org/docs/SymbolizerMarkupFormat.html
175f757f3fSDimitry Andric //===----------------------------------------------------------------------===//
1868d75effSDimitry Andric 
195f757f3fSDimitry Andric #include "sanitizer_symbolizer_markup.h"
205f757f3fSDimitry Andric 
215f757f3fSDimitry Andric #include "sanitizer_common.h"
225f757f3fSDimitry Andric #include "sanitizer_symbolizer.h"
235f757f3fSDimitry Andric #include "sanitizer_symbolizer_markup_constants.h"
245f757f3fSDimitry Andric 
255f757f3fSDimitry Andric namespace __sanitizer {
265f757f3fSDimitry Andric 
RenderData(InternalScopedString * buffer,const char * format,const DataInfo * DI,const char * strip_path_prefix)275f757f3fSDimitry Andric void MarkupStackTracePrinter::RenderData(InternalScopedString *buffer,
285f757f3fSDimitry Andric                                          const char *format, const DataInfo *DI,
295f757f3fSDimitry Andric                                          const char *strip_path_prefix) {
305f757f3fSDimitry Andric   RenderContext(buffer);
31*f08bf5a3SDimitry Andric   buffer->AppendF(kFormatData, reinterpret_cast<void *>(DI->start));
3268d75effSDimitry Andric }
3368d75effSDimitry Andric 
RenderNeedsSymbolization(const char * format)345f757f3fSDimitry Andric bool MarkupStackTracePrinter::RenderNeedsSymbolization(const char *format) {
3568d75effSDimitry Andric   return false;
3668d75effSDimitry Andric }
3768d75effSDimitry Andric 
385f757f3fSDimitry Andric // We don't support the stack_trace_format flag at all.
RenderFrame(InternalScopedString * buffer,const char * format,int frame_no,uptr address,const AddressInfo * info,bool vs_style,const char * strip_path_prefix)395f757f3fSDimitry Andric void MarkupStackTracePrinter::RenderFrame(InternalScopedString *buffer,
405f757f3fSDimitry Andric                                           const char *format, int frame_no,
415f757f3fSDimitry Andric                                           uptr address, const AddressInfo *info,
425f757f3fSDimitry Andric                                           bool vs_style,
435f757f3fSDimitry Andric                                           const char *strip_path_prefix) {
445f757f3fSDimitry Andric   CHECK(!RenderNeedsSymbolization(format));
455f757f3fSDimitry Andric   RenderContext(buffer);
46*f08bf5a3SDimitry Andric   buffer->AppendF(kFormatFrame, frame_no, reinterpret_cast<void *>(address));
4768d75effSDimitry Andric }
4868d75effSDimitry Andric 
SymbolizePC(uptr addr,SymbolizedStack * stack)495f757f3fSDimitry Andric bool MarkupSymbolizerTool::SymbolizePC(uptr addr, SymbolizedStack *stack) {
505f757f3fSDimitry Andric   char buffer[kFormatFunctionMax];
51*f08bf5a3SDimitry Andric   internal_snprintf(buffer, sizeof(buffer), kFormatFunction,
52*f08bf5a3SDimitry Andric                     reinterpret_cast<void *>(addr));
535f757f3fSDimitry Andric   stack->info.function = internal_strdup(buffer);
545f757f3fSDimitry Andric   return true;
555f757f3fSDimitry Andric }
565f757f3fSDimitry Andric 
SymbolizeData(uptr addr,DataInfo * info)575f757f3fSDimitry Andric bool MarkupSymbolizerTool::SymbolizeData(uptr addr, DataInfo *info) {
5868d75effSDimitry Andric   info->Clear();
5968d75effSDimitry Andric   info->start = addr;
6068d75effSDimitry Andric   return true;
6168d75effSDimitry Andric }
6268d75effSDimitry Andric 
Demangle(const char * name)635f757f3fSDimitry Andric const char *MarkupSymbolizerTool::Demangle(const char *name) {
645f757f3fSDimitry Andric   static char buffer[kFormatDemangleMax];
655f757f3fSDimitry Andric   internal_snprintf(buffer, sizeof(buffer), kFormatDemangle, name);
665f757f3fSDimitry Andric   return buffer;
6768d75effSDimitry Andric }
6868d75effSDimitry Andric 
695f757f3fSDimitry Andric // Fuchsia's implementation of symbolizer markup doesn't need to emit contextual
705f757f3fSDimitry Andric // elements at this point.
715f757f3fSDimitry Andric // Fuchsia's logging infrastructure emits enough information about
725f757f3fSDimitry Andric // process memory layout that a post-processing filter can do the
735f757f3fSDimitry Andric // symbolization and pretty-print the markup.
745f757f3fSDimitry Andric #if !SANITIZER_FUCHSIA
75e8d8bef9SDimitry Andric 
ModulesEq(const LoadedModule & module,const RenderedModule & renderedModule)765f757f3fSDimitry Andric static bool ModulesEq(const LoadedModule &module,
775f757f3fSDimitry Andric                       const RenderedModule &renderedModule) {
785f757f3fSDimitry Andric   return module.base_address() == renderedModule.base_address &&
795f757f3fSDimitry Andric          internal_memcmp(module.uuid(), renderedModule.uuid,
805f757f3fSDimitry Andric                          module.uuid_size()) == 0 &&
815f757f3fSDimitry Andric          internal_strcmp(module.full_name(), renderedModule.full_name) == 0;
8268d75effSDimitry Andric }
8368d75effSDimitry Andric 
ModuleHasBeenRendered(const LoadedModule & module,const InternalMmapVectorNoCtor<RenderedModule> & renderedModules)845f757f3fSDimitry Andric static bool ModuleHasBeenRendered(
855f757f3fSDimitry Andric     const LoadedModule &module,
865f757f3fSDimitry Andric     const InternalMmapVectorNoCtor<RenderedModule> &renderedModules) {
875f757f3fSDimitry Andric   for (const auto &renderedModule : renderedModules)
885f757f3fSDimitry Andric     if (ModulesEq(module, renderedModule))
895f757f3fSDimitry Andric       return true;
905f757f3fSDimitry Andric 
915f757f3fSDimitry Andric   return false;
9268d75effSDimitry Andric }
9368d75effSDimitry Andric 
RenderModule(InternalScopedString * buffer,const LoadedModule & module,uptr moduleId)945f757f3fSDimitry Andric static void RenderModule(InternalScopedString *buffer,
955f757f3fSDimitry Andric                          const LoadedModule &module, uptr moduleId) {
965f757f3fSDimitry Andric   InternalScopedString buildIdBuffer;
975f757f3fSDimitry Andric   for (uptr i = 0; i < module.uuid_size(); i++)
985f757f3fSDimitry Andric     buildIdBuffer.AppendF("%02x", module.uuid()[i]);
9968d75effSDimitry Andric 
1005f757f3fSDimitry Andric   buffer->AppendF(kFormatModule, moduleId, module.full_name(),
1015f757f3fSDimitry Andric                   buildIdBuffer.data());
1025f757f3fSDimitry Andric   buffer->Append("\n");
10368d75effSDimitry Andric }
10468d75effSDimitry Andric 
RenderMmaps(InternalScopedString * buffer,const LoadedModule & module,uptr moduleId)1055f757f3fSDimitry Andric static void RenderMmaps(InternalScopedString *buffer,
1065f757f3fSDimitry Andric                         const LoadedModule &module, uptr moduleId) {
1075f757f3fSDimitry Andric   InternalScopedString accessBuffer;
1085f757f3fSDimitry Andric 
1095f757f3fSDimitry Andric   // All module mmaps are readable at least
1105f757f3fSDimitry Andric   for (const auto &range : module.ranges()) {
1115f757f3fSDimitry Andric     accessBuffer.Append("r");
1125f757f3fSDimitry Andric     if (range.writable)
1135f757f3fSDimitry Andric       accessBuffer.Append("w");
1145f757f3fSDimitry Andric     if (range.executable)
1155f757f3fSDimitry Andric       accessBuffer.Append("x");
1165f757f3fSDimitry Andric 
1175f757f3fSDimitry Andric     //{{{mmap:%starting_addr:%size_in_hex:load:%moduleId:r%(w|x):%relative_addr}}}
1185f757f3fSDimitry Andric 
1195f757f3fSDimitry Andric     // module.base_address == dlpi_addr
1205f757f3fSDimitry Andric     // range.beg == dlpi_addr + p_vaddr
1215f757f3fSDimitry Andric     // relative address == p_vaddr == range.beg - module.base_address
122*f08bf5a3SDimitry Andric     buffer->AppendF(kFormatMmap, reinterpret_cast<void *>(range.beg),
123*f08bf5a3SDimitry Andric                     range.end - range.beg, static_cast<int>(moduleId),
1245f757f3fSDimitry Andric                     accessBuffer.data(), range.beg - module.base_address());
1255f757f3fSDimitry Andric 
1265f757f3fSDimitry Andric     buffer->Append("\n");
1275f757f3fSDimitry Andric     accessBuffer.clear();
1285f757f3fSDimitry Andric   }
12968d75effSDimitry Andric }
13068d75effSDimitry Andric 
RenderContext(InternalScopedString * buffer)1315f757f3fSDimitry Andric void MarkupStackTracePrinter::RenderContext(InternalScopedString *buffer) {
1325f757f3fSDimitry Andric   if (renderedModules_.size() == 0)
1335f757f3fSDimitry Andric     buffer->Append("{{{reset}}}\n");
1345f757f3fSDimitry Andric 
1355f757f3fSDimitry Andric   const auto &modules = Symbolizer::GetOrInit()->GetRefreshedListOfModules();
1365f757f3fSDimitry Andric 
1375f757f3fSDimitry Andric   for (const auto &module : modules) {
1385f757f3fSDimitry Andric     if (ModuleHasBeenRendered(module, renderedModules_))
1395f757f3fSDimitry Andric       continue;
1405f757f3fSDimitry Andric 
1415f757f3fSDimitry Andric     // symbolizer markup id, used to refer to this modules from other contextual
1425f757f3fSDimitry Andric     // elements
1435f757f3fSDimitry Andric     uptr moduleId = renderedModules_.size();
1445f757f3fSDimitry Andric 
1455f757f3fSDimitry Andric     RenderModule(buffer, module, moduleId);
1465f757f3fSDimitry Andric     RenderMmaps(buffer, module, moduleId);
1475f757f3fSDimitry Andric 
1485f757f3fSDimitry Andric     renderedModules_.push_back({
1495f757f3fSDimitry Andric         internal_strdup(module.full_name()),
1505f757f3fSDimitry Andric         module.base_address(),
1515f757f3fSDimitry Andric         {},
1525f757f3fSDimitry Andric     });
1535f757f3fSDimitry Andric 
1545f757f3fSDimitry Andric     // kModuleUUIDSize is the size of curModule.uuid
1555f757f3fSDimitry Andric     CHECK_GE(kModuleUUIDSize, module.uuid_size());
1565f757f3fSDimitry Andric     internal_memcpy(renderedModules_.back().uuid, module.uuid(),
1575f757f3fSDimitry Andric                     module.uuid_size());
15868d75effSDimitry Andric   }
1595f757f3fSDimitry Andric }
1605f757f3fSDimitry Andric #endif  // !SANITIZER_FUCHSIA
16168d75effSDimitry Andric 
16268d75effSDimitry Andric }  // namespace __sanitizer
163