diff options
Diffstat (limited to 'contrib/llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.h')
-rw-r--r-- | contrib/llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.h | 247 |
1 files changed, 247 insertions, 0 deletions
diff --git a/contrib/llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.h b/contrib/llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.h new file mode 100644 index 000000000000..16ef2f2fd717 --- /dev/null +++ b/contrib/llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.h @@ -0,0 +1,247 @@ +//===-- 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; + u8 uuid[kModuleUUIDSize]; + uptr uuid_size; + + 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); + void FillModuleInfo(const LoadedModule &mod); + uptr module_base() const { return address - module_offset; } +}; + +// 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(); +}; + +class SymbolizedStackHolder { + SymbolizedStack *Stack; + + void clear() { + if (Stack) + Stack->ClearAll(); + } + + public: + explicit SymbolizedStackHolder(SymbolizedStack *Stack = nullptr) + : Stack(Stack) {} + ~SymbolizedStackHolder() { clear(); } + void reset(SymbolizedStack *S = nullptr) { + if (Stack != S) + clear(); + Stack = S; + } + const SymbolizedStack *get() const { return Stack; } +}; + +// 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. Never returns nullptr. + 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(); + + const ListOfModules &GetRefreshedListOfModules(); + + 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, returns nullptr on failure. + 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_; + int errno_; // Backup errno in case symbolizer change the value. + }; +}; + +#ifdef SANITIZER_WINDOWS +void InitializeDbgHelpIfNeeded(); +#endif + +} // namespace __sanitizer + +#endif // SANITIZER_SYMBOLIZER_H |