//===-- sanitizer_symbolizer_internal.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 // //===----------------------------------------------------------------------===// // // Header for internal classes and functions to be used by implementations of // symbolizers. // //===----------------------------------------------------------------------===// #ifndef SANITIZER_SYMBOLIZER_INTERNAL_H #define SANITIZER_SYMBOLIZER_INTERNAL_H #include "sanitizer_symbolizer.h" #include "sanitizer_file.h" #include "sanitizer_vector.h" namespace __sanitizer { // Parsing helpers, 'str' is searched for delimiter(s) and a string or uptr // is extracted. When extracting a string, a newly allocated (using // InternalAlloc) and null-terminataed buffer is returned. They return a pointer // to the next characted after the found delimiter. const char *ExtractToken(const char *str, const char *delims, char **result); const char *ExtractInt(const char *str, const char *delims, int *result); const char *ExtractUptr(const char *str, const char *delims, uptr *result); const char *ExtractTokenUpToDelimiter(const char *str, const char *delimiter, char **result); const char *DemangleSwiftAndCXX(const char *name); // SymbolizerTool is an interface that is implemented by individual "tools" // that can perform symbolication (external llvm-symbolizer, libbacktrace, // Windows DbgHelp symbolizer, etc.). class SymbolizerTool { public: // The main |Symbolizer| class implements a "fallback chain" of symbolizer // tools. In a request to symbolize an address, if one tool returns false, // the next tool in the chain will be tried. SymbolizerTool *next; SymbolizerTool() : next(nullptr) { } // Can't declare pure virtual functions in sanitizer runtimes: // __cxa_pure_virtual might be unavailable. // The |stack| parameter is inout. It is pre-filled with the address, // module base and module offset values and is to be used to construct // other stack frames. virtual bool SymbolizePC(uptr addr, SymbolizedStack *stack) { UNIMPLEMENTED(); } // The |info| parameter is inout. It is pre-filled with the module base // and module offset values. virtual bool SymbolizeData(uptr addr, DataInfo *info) { UNIMPLEMENTED(); } virtual bool SymbolizeFrame(uptr addr, FrameInfo *info) { return false; } virtual void Flush() {} // Return nullptr to fallback to the default platform-specific demangler. virtual const char *Demangle(const char *name) { return nullptr; } // Called during the LateInitialize phase of Sanitizer initialization. // Usually this is a safe place to call code that might need to use user // memory allocators. virtual void LateInitialize() {} }; // SymbolizerProcess encapsulates communication between the tool and // external symbolizer program, running in a different subprocess. // SymbolizerProcess may not be used from two threads simultaneously. class SymbolizerProcess { public: explicit SymbolizerProcess(const char *path, bool use_posix_spawn = false); const char *SendCommand(const char *command); protected: /// The maximum number of arguments required to invoke a tool process. static const unsigned kArgVMax = 6; // Customizable by subclasses. virtual bool StartSymbolizerSubprocess(); virtual bool ReadFromSymbolizer(char *buffer, uptr max_length); // Return the environment to run the symbolizer in. virtual char **GetEnvP() { return GetEnviron(); } private: virtual bool ReachedEndOfOutput(const char *buffer, uptr length) const { UNIMPLEMENTED(); } /// Fill in an argv array to invoke the child process. virtual void GetArgV(const char *path_to_binary, const char *(&argv)[kArgVMax]) const { UNIMPLEMENTED(); } bool Restart(); const char *SendCommandImpl(const char *command); bool WriteToSymbolizer(const char *buffer, uptr length); const char *path_; fd_t input_fd_; fd_t output_fd_; static const uptr kBufferSize = 16 * 1024; char buffer_[kBufferSize]; static const uptr kMaxTimesRestarted = 5; static const int kSymbolizerStartupTimeMillis = 10; uptr times_restarted_; bool failed_to_start_; bool reported_invalid_path_; bool use_posix_spawn_; }; class LLVMSymbolizerProcess; // This tool invokes llvm-symbolizer in a subprocess. It should be as portable // as the llvm-symbolizer tool is. class LLVMSymbolizer : public SymbolizerTool { public: explicit LLVMSymbolizer(const char *path, LowLevelAllocator *allocator); bool SymbolizePC(uptr addr, SymbolizedStack *stack) override; bool SymbolizeData(uptr addr, DataInfo *info) override; bool SymbolizeFrame(uptr addr, FrameInfo *info) override; private: const char *FormatAndSendCommand(const char *command_prefix, const char *module_name, uptr module_offset, ModuleArch arch); LLVMSymbolizerProcess *symbolizer_process_; static const uptr kBufferSize = 16 * 1024; char buffer_[kBufferSize]; }; // Parses one or more two-line strings in the following format: // // :[:] // Used by LLVMSymbolizer, Addr2LinePool and InternalSymbolizer, since all of // them use the same output format. Returns true if any useful debug // information was found. void ParseSymbolizePCOutput(const char *str, SymbolizedStack *res); // Parses a two-line string in the following format: // // // Used by LLVMSymbolizer and InternalSymbolizer. void ParseSymbolizeDataOutput(const char *str, DataInfo *info); } // namespace __sanitizer #endif // SANITIZER_SYMBOLIZER_INTERNAL_H