248 lines · c
1//===-- sanitizer_symbolizer.h ----------------------------------*- C++ -*-===//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// Symbolizer is used by sanitizers to map instruction address to a location in10// source code at run-time. Symbolizer either uses __sanitizer_symbolize_*11// defined in the program, or (if they are missing) tries to find and12// launch "llvm-symbolizer" commandline tool in a separate process and13// communicate with it.14//15// Generally we should try to avoid calling system library functions during16// symbolization (and use their replacements from sanitizer_libc.h instead).17//===----------------------------------------------------------------------===//18#ifndef SANITIZER_SYMBOLIZER_H19#define SANITIZER_SYMBOLIZER_H20 21#include "sanitizer_common.h"22#include "sanitizer_mutex.h"23#include "sanitizer_vector.h"24 25namespace __sanitizer {26 27struct AddressInfo {28 // Owns all the string members. Storage for them is29 // (de)allocated using sanitizer internal allocator.30 uptr address;31 32 char *module;33 uptr module_offset;34 ModuleArch module_arch;35 u8 uuid[kModuleUUIDSize];36 uptr uuid_size;37 38 static const uptr kUnknown = ~(uptr)0;39 char *function;40 uptr function_offset;41 42 char *file;43 int line;44 int column;45 46 AddressInfo();47 // Deletes all strings and resets all fields.48 void Clear();49 void FillModuleInfo(const char *mod_name, uptr mod_offset, ModuleArch arch);50 void FillModuleInfo(const LoadedModule &mod);51 uptr module_base() const { return address - module_offset; }52};53 54// Linked list of symbolized frames (each frame is described by AddressInfo).55struct SymbolizedStack {56 SymbolizedStack *next;57 AddressInfo info;58 static SymbolizedStack *New(uptr addr);59 // Deletes current, and all subsequent frames in the linked list.60 // The object cannot be accessed after the call to this function.61 void ClearAll();62 63 private:64 SymbolizedStack();65};66 67class SymbolizedStackHolder {68 SymbolizedStack *Stack;69 70 void clear() {71 if (Stack)72 Stack->ClearAll();73 }74 75 public:76 explicit SymbolizedStackHolder(SymbolizedStack *Stack = nullptr)77 : Stack(Stack) {}78 ~SymbolizedStackHolder() { clear(); }79 void reset(SymbolizedStack *S = nullptr) {80 if (Stack != S)81 clear();82 Stack = S;83 }84 const SymbolizedStack *get() const { return Stack; }85};86 87// For now, DataInfo is used to describe global variable.88struct DataInfo {89 // Owns all the string members. Storage for them is90 // (de)allocated using sanitizer internal allocator.91 char *module;92 uptr module_offset;93 ModuleArch module_arch;94 95 char *file;96 uptr line;97 char *name;98 uptr start;99 uptr size;100 101 DataInfo();102 void Clear();103};104 105struct LocalInfo {106 char *function_name = nullptr;107 char *name = nullptr;108 char *decl_file = nullptr;109 unsigned decl_line = 0;110 111 bool has_frame_offset = false;112 bool has_size = false;113 bool has_tag_offset = false;114 115 sptr frame_offset;116 uptr size;117 uptr tag_offset;118 119 void Clear();120};121 122struct FrameInfo {123 char *module;124 uptr module_offset;125 ModuleArch module_arch;126 127 InternalMmapVector<LocalInfo> locals;128 void Clear();129};130 131class SymbolizerTool;132 133class Symbolizer final {134 public:135 /// Initialize and return platform-specific implementation of symbolizer136 /// (if it wasn't already initialized).137 static Symbolizer *GetOrInit();138 static void LateInitialize();139 // Returns a list of symbolized frames for a given address (containing140 // all inlined functions, if necessary).141 SymbolizedStack *SymbolizePC(uptr address);142 bool SymbolizeData(uptr address, DataInfo *info);143 bool SymbolizeFrame(uptr address, FrameInfo *info);144 145 // The module names Symbolizer returns are stable and unique for every given146 // module. It is safe to store and compare them as pointers.147 bool GetModuleNameAndOffsetForPC(uptr pc, const char **module_name,148 uptr *module_address);149 const char *GetModuleNameForPc(uptr pc) {150 const char *module_name = nullptr;151 uptr unused;152 if (GetModuleNameAndOffsetForPC(pc, &module_name, &unused))153 return module_name;154 return nullptr;155 }156 157 // Release internal caches (if any).158 void Flush();159 // Attempts to demangle the provided C++ mangled name. Never returns nullptr.160 const char *Demangle(const char *name);161 162 // Allow user to install hooks that would be called before/after Symbolizer163 // does the actual file/line info fetching. Specific sanitizers may need this164 // to distinguish system library calls made in user code from calls made165 // during in-process symbolization.166 typedef void (*StartSymbolizationHook)();167 typedef void (*EndSymbolizationHook)();168 // May be called at most once.169 void AddHooks(StartSymbolizationHook start_hook,170 EndSymbolizationHook end_hook);171 172 void RefreshModules();173 const LoadedModule *FindModuleForAddress(uptr address);174 175 void InvalidateModuleList();176 177 const ListOfModules &GetRefreshedListOfModules();178 179 private:180 // GetModuleNameAndOffsetForPC has to return a string to the caller.181 // Since the corresponding module might get unloaded later, we should create182 // our owned copies of the strings that we can safely return.183 // ModuleNameOwner does not provide any synchronization, thus calls to184 // its method should be protected by |mu_|.185 class ModuleNameOwner {186 public:187 explicit ModuleNameOwner(Mutex *synchronized_by)188 : mu_(synchronized_by), last_match_(nullptr) {189 storage_.reserve(kInitialCapacity);190 }191 const char *GetOwnedCopy(const char *str);192 193 private:194 static const uptr kInitialCapacity = 1000;195 196 Mutex *mu_;197 const char *last_match_ SANITIZER_GUARDED_BY(mu_);198 InternalMmapVector<const char *> storage_ SANITIZER_GUARDED_BY(*mu_);199 } module_names_;200 201 /// Platform-specific function for creating a Symbolizer object.202 static Symbolizer *PlatformInit();203 204 bool FindModuleNameAndOffsetForAddress(uptr address, const char **module_name,205 uptr *module_offset,206 ModuleArch *module_arch);207 ListOfModules modules_;208 ListOfModules fallback_modules_;209 // If stale, need to reload the modules before looking up addresses.210 bool modules_fresh_;211 212 // Platform-specific default demangler, returns nullptr on failure.213 const char *PlatformDemangle(const char *name);214 215 static Symbolizer *symbolizer_;216 static StaticSpinMutex init_mu_;217 218 // Mutex locked from public methods of |Symbolizer|, so that the internals219 // (including individual symbolizer tools and platform-specific methods) are220 // always synchronized.221 Mutex mu_;222 223 IntrusiveList<SymbolizerTool> tools_ SANITIZER_GUARDED_BY(mu_);224 225 explicit Symbolizer(IntrusiveList<SymbolizerTool> tools);226 227 static LowLevelAllocator symbolizer_allocator_;228 229 StartSymbolizationHook start_hook_;230 EndSymbolizationHook end_hook_;231 class SymbolizerScope {232 public:233 explicit SymbolizerScope(const Symbolizer *sym);234 ~SymbolizerScope();235 private:236 const Symbolizer *sym_;237 int errno_; // Backup errno in case symbolizer change the value.238 };239};240 241#ifdef SANITIZER_WINDOWS242void InitializeDbgHelpIfNeeded();243#endif244 245} // namespace __sanitizer246 247#endif // SANITIZER_SYMBOLIZER_H248