michael@0: // Copyright (c) 2010 Google Inc. michael@0: // All rights reserved. michael@0: // michael@0: // Redistribution and use in source and binary forms, with or without michael@0: // modification, are permitted provided that the following conditions are michael@0: // met: michael@0: // michael@0: // * Redistributions of source code must retain the above copyright michael@0: // notice, this list of conditions and the following disclaimer. michael@0: // * Redistributions in binary form must reproduce the above michael@0: // copyright notice, this list of conditions and the following disclaimer michael@0: // in the documentation and/or other materials provided with the michael@0: // distribution. michael@0: // * Neither the name of Google Inc. nor the names of its michael@0: // contributors may be used to endorse or promote products derived from michael@0: // this software without specific prior written permission. michael@0: // michael@0: // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS michael@0: // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT michael@0: // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR michael@0: // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT michael@0: // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, michael@0: // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT michael@0: // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, michael@0: // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY michael@0: // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT michael@0: // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE michael@0: // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. michael@0: michael@0: // stackwalker.h: Generic stackwalker. michael@0: // michael@0: // The Stackwalker class is an abstract base class providing common generic michael@0: // methods that apply to stacks from all systems. Specific implementations michael@0: // will extend this class by providing GetContextFrame and GetCallerFrame michael@0: // methods to fill in system-specific data in a StackFrame structure. michael@0: // Stackwalker assembles these StackFrame strucutres into a CallStack. michael@0: // michael@0: // Author: Mark Mentovai michael@0: michael@0: michael@0: #ifndef GOOGLE_BREAKPAD_PROCESSOR_STACKWALKER_H__ michael@0: #define GOOGLE_BREAKPAD_PROCESSOR_STACKWALKER_H__ michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #include "common/using_std_string.h" michael@0: #include "google_breakpad/common/breakpad_types.h" michael@0: #include "google_breakpad/processor/code_modules.h" michael@0: #include "google_breakpad/processor/memory_region.h" michael@0: #include "google_breakpad/processor/stack_frame_symbolizer.h" michael@0: michael@0: namespace google_breakpad { michael@0: michael@0: class CallStack; michael@0: class MinidumpContext; michael@0: class StackFrameSymbolizer; michael@0: michael@0: using std::set; michael@0: using std::vector; michael@0: michael@0: class Stackwalker { michael@0: public: michael@0: virtual ~Stackwalker() {} michael@0: michael@0: // Populates the given CallStack by calling GetContextFrame and michael@0: // GetCallerFrame. The frames are further processed to fill all available michael@0: // data. Returns true if the stackwalk completed, or false if it was michael@0: // interrupted by SymbolSupplier::GetSymbolFile(). michael@0: // Upon return, modules_without_symbols will be populated with pointers to michael@0: // the code modules (CodeModule*) that DON'T have symbols. michael@0: // modules_without_symbols DOES NOT take ownership of the code modules. michael@0: // The lifetime of these code modules is the same as the lifetime of the michael@0: // CodeModules passed to the StackWalker constructor (which currently michael@0: // happens to be the lifetime of the Breakpad's ProcessingState object). michael@0: // There is a check for duplicate modules so no duplicates are expected. michael@0: bool Walk(CallStack* stack, michael@0: vector* modules_without_symbols); michael@0: michael@0: // Returns a new concrete subclass suitable for the CPU that a stack was michael@0: // generated on, according to the CPU type indicated by the context michael@0: // argument. If no suitable concrete subclass exists, returns NULL. michael@0: static Stackwalker* StackwalkerForCPU( michael@0: const SystemInfo* system_info, michael@0: MinidumpContext* context, michael@0: MemoryRegion* memory, michael@0: const CodeModules* modules, michael@0: StackFrameSymbolizer* resolver_helper); michael@0: michael@0: static void set_max_frames(uint32_t max_frames) { michael@0: max_frames_ = max_frames; michael@0: max_frames_set_ = true; michael@0: } michael@0: static uint32_t max_frames() { return max_frames_; } michael@0: michael@0: static void set_max_frames_scanned(uint32_t max_frames_scanned) { michael@0: max_frames_scanned_ = max_frames_scanned; michael@0: } michael@0: michael@0: protected: michael@0: // system_info identifies the operating system, NULL or empty if unknown. michael@0: // memory identifies a MemoryRegion that provides the stack memory michael@0: // for the stack to walk. modules, if non-NULL, is a CodeModules michael@0: // object that is used to look up which code module each stack frame is michael@0: // associated with. frame_symbolizer is a StackFrameSymbolizer object that michael@0: // encapsulates the logic of how source line resolver interacts with symbol michael@0: // supplier to symbolize stack frame and look up caller frame information michael@0: // (see stack_frame_symbolizer.h). michael@0: // frame_symbolizer MUST NOT be NULL (asserted). michael@0: Stackwalker(const SystemInfo* system_info, michael@0: MemoryRegion* memory, michael@0: const CodeModules* modules, michael@0: StackFrameSymbolizer* frame_symbolizer); michael@0: michael@0: // This can be used to filter out potential return addresses when michael@0: // the stack walker resorts to stack scanning. michael@0: // Returns true if any of: michael@0: // * This address is within a loaded module, but we don't have symbols michael@0: // for that module. michael@0: // * This address is within a loaded module for which we have symbols, michael@0: // and falls inside a function in that module. michael@0: // Returns false otherwise. michael@0: bool InstructionAddressSeemsValid(uint64_t address); michael@0: michael@0: // The default number of words to search through on the stack michael@0: // for a return address. michael@0: static const int kRASearchWords; michael@0: michael@0: template michael@0: bool ScanForReturnAddress(InstructionType location_start, michael@0: InstructionType* location_found, michael@0: InstructionType* ip_found) { michael@0: return ScanForReturnAddress(location_start, location_found, ip_found, michael@0: kRASearchWords); michael@0: } michael@0: michael@0: // Scan the stack starting at location_start, looking for an address michael@0: // that looks like a valid instruction pointer. Addresses must michael@0: // 1) be contained in the current stack memory michael@0: // 2) pass the checks in InstructionAddressSeemsValid michael@0: // michael@0: // Returns true if a valid-looking instruction pointer was found. michael@0: // When returning true, sets location_found to the address at which michael@0: // the value was found, and ip_found to the value contained at that michael@0: // location in memory. michael@0: template michael@0: bool ScanForReturnAddress(InstructionType location_start, michael@0: InstructionType* location_found, michael@0: InstructionType* ip_found, michael@0: int searchwords) { michael@0: for (InstructionType location = location_start; michael@0: location <= location_start + searchwords * sizeof(InstructionType); michael@0: location += sizeof(InstructionType)) { michael@0: InstructionType ip; michael@0: if (!memory_->GetMemoryAtAddress(location, &ip)) michael@0: break; michael@0: michael@0: if (modules_ && modules_->GetModuleForAddress(ip) && michael@0: InstructionAddressSeemsValid(ip)) { michael@0: *ip_found = ip; michael@0: *location_found = location; michael@0: return true; michael@0: } michael@0: } michael@0: // nothing found michael@0: return false; michael@0: } michael@0: michael@0: // Information about the system that produced the minidump. Subclasses michael@0: // and the SymbolSupplier may find this information useful. michael@0: const SystemInfo* system_info_; michael@0: michael@0: // The stack memory to walk. Subclasses will require this region to michael@0: // get information from the stack. michael@0: MemoryRegion* memory_; michael@0: michael@0: // A list of modules, for populating each StackFrame's module information. michael@0: // This field is optional and may be NULL. michael@0: const CodeModules* modules_; michael@0: michael@0: protected: michael@0: // The StackFrameSymbolizer implementation. michael@0: StackFrameSymbolizer* frame_symbolizer_; michael@0: michael@0: private: michael@0: // Obtains the context frame, the innermost called procedure in a stack michael@0: // trace. Returns NULL on failure. GetContextFrame allocates a new michael@0: // StackFrame (or StackFrame subclass), ownership of which is taken by michael@0: // the caller. michael@0: virtual StackFrame* GetContextFrame() = 0; michael@0: michael@0: // Obtains a caller frame. Each call to GetCallerFrame should return the michael@0: // frame that called the last frame returned by GetContextFrame or michael@0: // GetCallerFrame. To aid this purpose, stack contains the CallStack michael@0: // made of frames that have already been walked. GetCallerFrame should michael@0: // return NULL on failure or when there are no more caller frames (when michael@0: // the end of the stack has been reached). GetCallerFrame allocates a new michael@0: // StackFrame (or StackFrame subclass), ownership of which is taken by michael@0: // the caller. |stack_scan_allowed| controls whether stack scanning is michael@0: // an allowable frame-recovery method, since it is desirable to be able to michael@0: // disable stack scanning in performance-critical use cases. michael@0: virtual StackFrame* GetCallerFrame(const CallStack* stack, michael@0: bool stack_scan_allowed) = 0; michael@0: michael@0: // The maximum number of frames Stackwalker will walk through. michael@0: // This defaults to 1024 to prevent infinite loops. michael@0: static uint32_t max_frames_; michael@0: michael@0: // Keep track of whether max_frames_ has been set by the user, since michael@0: // it affects whether or not an error message is printed in the case michael@0: // where an unwind got stopped by the limit. michael@0: static bool max_frames_set_; michael@0: michael@0: // The maximum number of stack-scanned and otherwise untrustworthy michael@0: // frames allowed. Stack-scanning can be expensive, so the option to michael@0: // disable or limit it is helpful in cases where unwind performance is michael@0: // important. This defaults to 1024, the same as max_frames_. michael@0: static uint32_t max_frames_scanned_; michael@0: }; michael@0: michael@0: } // namespace google_breakpad michael@0: michael@0: michael@0: #endif // GOOGLE_BREAKPAD_PROCESSOR_STACKWALKER_H__