| //===-- sanitizer_symbolizer.h ----------------------------------*- C++ -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // Symbolizer is used by sanitizers to map instruction address to a location in |
| // source code at run-time. Symbolizer either uses __sanitizer_symbolize_* |
| // defined in the program, or (if they are missing) tries to find and |
| // launch "llvm-symbolizer" commandline tool in a separate process and |
| // communicate with it. |
| // |
| // Generally we should try to avoid calling system library functions during |
| // symbolization (and use their replacements from sanitizer_libc.h instead). |
| //===----------------------------------------------------------------------===// |
| #ifndef SANITIZER_SYMBOLIZER_H |
| #define SANITIZER_SYMBOLIZER_H |
| |
| #include "sanitizer_common.h" |
| #include "sanitizer_mutex.h" |
| #include "sanitizer_vector.h" |
| |
| namespace __sanitizer { |
| |
| struct AddressInfo { |
| // Owns all the string members. Storage for them is |
| // (de)allocated using sanitizer internal allocator. |
| uptr address; |
| |
| char *module; |
| uptr module_offset; |
| ModuleArch module_arch; |
| |
| static const uptr kUnknown = ~(uptr)0; |
| char *function; |
| uptr function_offset; |
| |
| char *file; |
| int line; |
| int column; |
| |
| AddressInfo(); |
| // Deletes all strings and resets all fields. |
| void Clear(); |
| void FillModuleInfo(const char *mod_name, uptr mod_offset, ModuleArch arch); |
| }; |
| |
| // Linked list of symbolized frames (each frame is described by AddressInfo). |
| struct SymbolizedStack { |
| SymbolizedStack *next; |
| AddressInfo info; |
| static SymbolizedStack *New(uptr addr); |
| // Deletes current, and all subsequent frames in the linked list. |
| // The object cannot be accessed after the call to this function. |
| void ClearAll(); |
| |
| private: |
| SymbolizedStack(); |
| }; |
| |
| // For now, DataInfo is used to describe global variable. |
| struct DataInfo { |
| // Owns all the string members. Storage for them is |
| // (de)allocated using sanitizer internal allocator. |
| char *module; |
| uptr module_offset; |
| ModuleArch module_arch; |
| |
| char *file; |
| uptr line; |
| char *name; |
| uptr start; |
| uptr size; |
| |
| DataInfo(); |
| void Clear(); |
| }; |
| |
| struct LocalInfo { |
| char *function_name = nullptr; |
| char *name = nullptr; |
| char *decl_file = nullptr; |
| unsigned decl_line = 0; |
| |
| bool has_frame_offset = false; |
| bool has_size = false; |
| bool has_tag_offset = false; |
| |
| sptr frame_offset; |
| uptr size; |
| uptr tag_offset; |
| |
| void Clear(); |
| }; |
| |
| struct FrameInfo { |
| char *module; |
| uptr module_offset; |
| ModuleArch module_arch; |
| |
| InternalMmapVector<LocalInfo> locals; |
| void Clear(); |
| }; |
| |
| class SymbolizerTool; |
| |
| class Symbolizer final { |
| public: |
| /// Initialize and return platform-specific implementation of symbolizer |
| /// (if it wasn't already initialized). |
| static Symbolizer *GetOrInit(); |
| static void LateInitialize(); |
| // Returns a list of symbolized frames for a given address (containing |
| // all inlined functions, if necessary). |
| SymbolizedStack *SymbolizePC(uptr address); |
| bool SymbolizeData(uptr address, DataInfo *info); |
| bool SymbolizeFrame(uptr address, FrameInfo *info); |
| |
| // The module names Symbolizer returns are stable and unique for every given |
| // module. It is safe to store and compare them as pointers. |
| bool GetModuleNameAndOffsetForPC(uptr pc, const char **module_name, |
| uptr *module_address); |
| const char *GetModuleNameForPc(uptr pc) { |
| const char *module_name = nullptr; |
| uptr unused; |
| if (GetModuleNameAndOffsetForPC(pc, &module_name, &unused)) |
| return module_name; |
| return nullptr; |
| } |
| |
| // Release internal caches (if any). |
| void Flush(); |
| // Attempts to demangle the provided C++ mangled name. |
| const char *Demangle(const char *name); |
| |
| // Allow user to install hooks that would be called before/after Symbolizer |
| // does the actual file/line info fetching. Specific sanitizers may need this |
| // to distinguish system library calls made in user code from calls made |
| // during in-process symbolization. |
| typedef void (*StartSymbolizationHook)(); |
| typedef void (*EndSymbolizationHook)(); |
| // May be called at most once. |
| void AddHooks(StartSymbolizationHook start_hook, |
| EndSymbolizationHook end_hook); |
| |
| void RefreshModules(); |
| const LoadedModule *FindModuleForAddress(uptr address); |
| |
| void InvalidateModuleList(); |
| |
| private: |
| // GetModuleNameAndOffsetForPC has to return a string to the caller. |
| // Since the corresponding module might get unloaded later, we should create |
| // our owned copies of the strings that we can safely return. |
| // ModuleNameOwner does not provide any synchronization, thus calls to |
| // its method should be protected by |mu_|. |
| class ModuleNameOwner { |
| public: |
| explicit ModuleNameOwner(Mutex *synchronized_by) |
| : last_match_(nullptr), mu_(synchronized_by) { |
| storage_.reserve(kInitialCapacity); |
| } |
| const char *GetOwnedCopy(const char *str); |
| |
| private: |
| static const uptr kInitialCapacity = 1000; |
| InternalMmapVector<const char*> storage_; |
| const char *last_match_; |
| |
| Mutex *mu_; |
| } module_names_; |
| |
| /// Platform-specific function for creating a Symbolizer object. |
| static Symbolizer *PlatformInit(); |
| |
| bool FindModuleNameAndOffsetForAddress(uptr address, const char **module_name, |
| uptr *module_offset, |
| ModuleArch *module_arch); |
| ListOfModules modules_; |
| ListOfModules fallback_modules_; |
| // If stale, need to reload the modules before looking up addresses. |
| bool modules_fresh_; |
| |
| // Platform-specific default demangler, must not return nullptr. |
| const char *PlatformDemangle(const char *name); |
| |
| static Symbolizer *symbolizer_; |
| static StaticSpinMutex init_mu_; |
| |
| // Mutex locked from public methods of |Symbolizer|, so that the internals |
| // (including individual symbolizer tools and platform-specific methods) are |
| // always synchronized. |
| Mutex mu_; |
| |
| IntrusiveList<SymbolizerTool> tools_; |
| |
| explicit Symbolizer(IntrusiveList<SymbolizerTool> tools); |
| |
| static LowLevelAllocator symbolizer_allocator_; |
| |
| StartSymbolizationHook start_hook_; |
| EndSymbolizationHook end_hook_; |
| class SymbolizerScope { |
| public: |
| explicit SymbolizerScope(const Symbolizer *sym); |
| ~SymbolizerScope(); |
| private: |
| const Symbolizer *sym_; |
| }; |
| |
| // Calls `LateInitialize()` on all items in `tools_`. |
| void LateInitializeTools(); |
| }; |
| |
| #ifdef SANITIZER_WINDOWS |
| void InitializeDbgHelpIfNeeded(); |
| #endif |
| |
| } // namespace __sanitizer |
| |
| #endif // SANITIZER_SYMBOLIZER_H |