michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set ts=8 sts=2 et sw=2 tw=80: */ michael@0: michael@0: // Copyright (c) 2006, 2010, 2012, 2013 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: // Original author: Jim Blandy michael@0: michael@0: // module.h: Define google_breakpad::Module. A Module holds debugging michael@0: // information, and can write that information out as a Breakpad michael@0: // symbol file. michael@0: michael@0: michael@0: // (C) Copyright Greg Colvin and Beman Dawes 1998, 1999. michael@0: // Copyright (c) 2001, 2002 Peter Dimov michael@0: // michael@0: // Permission to copy, use, modify, sell and distribute this software michael@0: // is granted provided this copyright notice appears in all copies. michael@0: // This software is provided "as is" without express or implied michael@0: // warranty, and with no claim as to its suitability for any purpose. michael@0: // michael@0: // See http://www.boost.org/libs/smart_ptr/scoped_ptr.htm for documentation. michael@0: // michael@0: michael@0: michael@0: // This file is derived from the following files in michael@0: // toolkit/crashreporter/google-breakpad: michael@0: // src/common/unique_string.h michael@0: // src/common/scoped_ptr.h michael@0: // src/common/module.h michael@0: michael@0: // External interface for the "Common" component of LUL. michael@0: michael@0: #ifndef LulCommonExt_h michael@0: #define LulCommonExt_h michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: #include // for std::ptrdiff_t michael@0: michael@0: #include "mozilla/Assertions.h" michael@0: #include "mozilla/NullPtr.h" michael@0: michael@0: namespace lul { michael@0: michael@0: //////////////////////////////////////////////////////////////// michael@0: // UniqueString michael@0: // michael@0: michael@0: // Abstract type michael@0: class UniqueString; michael@0: michael@0: // Unique-ify a string. |ToUniqueString| can never return nullptr. michael@0: const UniqueString* ToUniqueString(std::string); michael@0: michael@0: // Get the contained C string (debugging only) michael@0: const char* const FromUniqueString(const UniqueString*); michael@0: michael@0: // Some handy pre-uniqified strings. Z is an escape character: michael@0: // ZS '$' michael@0: // ZD '.' michael@0: // Zeq '=' michael@0: // Zplus '+' michael@0: // Zstar '*' michael@0: // Zslash '/' michael@0: // Zpercent '%' michael@0: // Zat '@' michael@0: // Zcaret '^' michael@0: michael@0: // Note that ustr__empty and (UniqueString*)nullptr are considered michael@0: // to be different. michael@0: // michael@0: // Unfortunately these have to be written as functions so as to michael@0: // make them safe to use in static initialisers. michael@0: michael@0: // "" michael@0: inline static const UniqueString* ustr__empty() { michael@0: static const UniqueString* us = nullptr; michael@0: if (!us) us = ToUniqueString(""); michael@0: return us; michael@0: } michael@0: michael@0: // ".cfa" michael@0: inline static const UniqueString* ustr__ZDcfa() { michael@0: static const UniqueString* us = nullptr; michael@0: if (!us) us = ToUniqueString(".cfa"); michael@0: return us; michael@0: } michael@0: michael@0: // ".ra" michael@0: inline static const UniqueString* ustr__ZDra() { michael@0: static const UniqueString* us = nullptr; michael@0: if (!us) us = ToUniqueString(".ra"); michael@0: return us; michael@0: } michael@0: michael@0: michael@0: //////////////////////////////////////////////////////////////// michael@0: // GUID michael@0: // michael@0: michael@0: typedef struct { michael@0: uint32_t data1; michael@0: uint16_t data2; michael@0: uint16_t data3; michael@0: uint8_t data4[8]; michael@0: } MDGUID; // GUID michael@0: michael@0: typedef MDGUID GUID; michael@0: michael@0: michael@0: //////////////////////////////////////////////////////////////// michael@0: // scoped_ptr michael@0: // michael@0: michael@0: // scoped_ptr mimics a built-in pointer except that it guarantees deletion michael@0: // of the object pointed to, either on destruction of the scoped_ptr or via michael@0: // an explicit reset(). scoped_ptr is a simple solution for simple needs; michael@0: // use shared_ptr or std::auto_ptr if your needs are more complex. michael@0: michael@0: // *** NOTE *** michael@0: // If your scoped_ptr is a class member of class FOO pointing to a michael@0: // forward declared type BAR (as shown below), then you MUST use a non-inlined michael@0: // version of the destructor. The destructor of a scoped_ptr (called from michael@0: // FOO's destructor) must have a complete definition of BAR in order to michael@0: // destroy it. Example: michael@0: // michael@0: // -- foo.h -- michael@0: // class BAR; michael@0: // michael@0: // class FOO { michael@0: // public: michael@0: // FOO(); michael@0: // ~FOO(); // Required for sources that instantiate class FOO to compile! michael@0: // michael@0: // private: michael@0: // scoped_ptr bar_; michael@0: // }; michael@0: // michael@0: // -- foo.cc -- michael@0: // #include "foo.h" michael@0: // FOO::~FOO() {} // Empty, but must be non-inlined to FOO's class definition. michael@0: michael@0: // scoped_ptr_malloc added by Google michael@0: // When one of these goes out of scope, instead of doing a delete or michael@0: // delete[], it calls free(). scoped_ptr_malloc is likely to see michael@0: // much more use than any other specializations. michael@0: michael@0: // release() added by Google michael@0: // Use this to conditionally transfer ownership of a heap-allocated object michael@0: // to the caller, usually on method success. michael@0: michael@0: template michael@0: class scoped_ptr { michael@0: private: michael@0: michael@0: T* ptr; michael@0: michael@0: scoped_ptr(scoped_ptr const &); michael@0: scoped_ptr & operator=(scoped_ptr const &); michael@0: michael@0: public: michael@0: michael@0: typedef T element_type; michael@0: michael@0: explicit scoped_ptr(T* p = 0): ptr(p) {} michael@0: michael@0: ~scoped_ptr() { michael@0: delete ptr; michael@0: } michael@0: michael@0: void reset(T* p = 0) { michael@0: if (ptr != p) { michael@0: delete ptr; michael@0: ptr = p; michael@0: } michael@0: } michael@0: michael@0: T& operator*() const { michael@0: MOZ_ASSERT(ptr != 0); michael@0: return *ptr; michael@0: } michael@0: michael@0: T* operator->() const { michael@0: MOZ_ASSERT(ptr != 0); michael@0: return ptr; michael@0: } michael@0: michael@0: bool operator==(T* p) const { michael@0: return ptr == p; michael@0: } michael@0: michael@0: bool operator!=(T* p) const { michael@0: return ptr != p; michael@0: } michael@0: michael@0: T* get() const { michael@0: return ptr; michael@0: } michael@0: michael@0: void swap(scoped_ptr & b) { michael@0: T* tmp = b.ptr; michael@0: b.ptr = ptr; michael@0: ptr = tmp; michael@0: } michael@0: michael@0: T* release() { michael@0: T* tmp = ptr; michael@0: ptr = 0; michael@0: return tmp; michael@0: } michael@0: michael@0: private: michael@0: michael@0: // no reason to use these: each scoped_ptr should have its own object michael@0: template bool operator==(scoped_ptr const& p) const; michael@0: template bool operator!=(scoped_ptr const& p) const; michael@0: }; michael@0: michael@0: template inline michael@0: void swap(scoped_ptr& a, scoped_ptr& b) { michael@0: a.swap(b); michael@0: } michael@0: michael@0: template inline michael@0: bool operator==(T* p, const scoped_ptr& b) { michael@0: return p == b.get(); michael@0: } michael@0: michael@0: template inline michael@0: bool operator!=(T* p, const scoped_ptr& b) { michael@0: return p != b.get(); michael@0: } michael@0: michael@0: // scoped_array extends scoped_ptr to arrays. Deletion of the array pointed to michael@0: // is guaranteed, either on destruction of the scoped_array or via an explicit michael@0: // reset(). Use shared_array or std::vector if your needs are more complex. michael@0: michael@0: template michael@0: class scoped_array { michael@0: private: michael@0: michael@0: T* ptr; michael@0: michael@0: scoped_array(scoped_array const &); michael@0: scoped_array & operator=(scoped_array const &); michael@0: michael@0: public: michael@0: michael@0: typedef T element_type; michael@0: michael@0: explicit scoped_array(T* p = 0) : ptr(p) {} michael@0: michael@0: ~scoped_array() { michael@0: delete[] ptr; michael@0: } michael@0: michael@0: void reset(T* p = 0) { michael@0: if (ptr != p) { michael@0: delete [] ptr; michael@0: ptr = p; michael@0: } michael@0: } michael@0: michael@0: T& operator[](std::ptrdiff_t i) const { michael@0: MOZ_ASSERT(ptr != 0); michael@0: MOZ_ASSERT(i >= 0); michael@0: return ptr[i]; michael@0: } michael@0: michael@0: bool operator==(T* p) const { michael@0: return ptr == p; michael@0: } michael@0: michael@0: bool operator!=(T* p) const { michael@0: return ptr != p; michael@0: } michael@0: michael@0: T* get() const { michael@0: return ptr; michael@0: } michael@0: michael@0: void swap(scoped_array & b) { michael@0: T* tmp = b.ptr; michael@0: b.ptr = ptr; michael@0: ptr = tmp; michael@0: } michael@0: michael@0: T* release() { michael@0: T* tmp = ptr; michael@0: ptr = 0; michael@0: return tmp; michael@0: } michael@0: michael@0: private: michael@0: michael@0: // no reason to use these: each scoped_array should have its own object michael@0: template bool operator==(scoped_array const& p) const; michael@0: template bool operator!=(scoped_array const& p) const; michael@0: }; michael@0: michael@0: template inline michael@0: void swap(scoped_array& a, scoped_array& b) { michael@0: a.swap(b); michael@0: } michael@0: michael@0: template inline michael@0: bool operator==(T* p, const scoped_array& b) { michael@0: return p == b.get(); michael@0: } michael@0: michael@0: template inline michael@0: bool operator!=(T* p, const scoped_array& b) { michael@0: return p != b.get(); michael@0: } michael@0: michael@0: michael@0: // This class wraps the c library function free() in a class that can be michael@0: // passed as a template argument to scoped_ptr_malloc below. michael@0: class ScopedPtrMallocFree { michael@0: public: michael@0: inline void operator()(void* x) const { michael@0: free(x); michael@0: } michael@0: }; michael@0: michael@0: // scoped_ptr_malloc<> is similar to scoped_ptr<>, but it accepts a michael@0: // second template argument, the functor used to free the object. michael@0: michael@0: template michael@0: class scoped_ptr_malloc { michael@0: private: michael@0: michael@0: T* ptr; michael@0: michael@0: scoped_ptr_malloc(scoped_ptr_malloc const &); michael@0: scoped_ptr_malloc & operator=(scoped_ptr_malloc const &); michael@0: michael@0: public: michael@0: michael@0: typedef T element_type; michael@0: michael@0: explicit scoped_ptr_malloc(T* p = 0): ptr(p) {} michael@0: michael@0: ~scoped_ptr_malloc() { michael@0: free_((void*) ptr); michael@0: } michael@0: michael@0: void reset(T* p = 0) { michael@0: if (ptr != p) { michael@0: free_((void*) ptr); michael@0: ptr = p; michael@0: } michael@0: } michael@0: michael@0: T& operator*() const { michael@0: MOZ_ASSERT(ptr != 0); michael@0: return *ptr; michael@0: } michael@0: michael@0: T* operator->() const { michael@0: MOZ_ASSERT(ptr != 0); michael@0: return ptr; michael@0: } michael@0: michael@0: bool operator==(T* p) const { michael@0: return ptr == p; michael@0: } michael@0: michael@0: bool operator!=(T* p) const { michael@0: return ptr != p; michael@0: } michael@0: michael@0: T* get() const { michael@0: return ptr; michael@0: } michael@0: michael@0: void swap(scoped_ptr_malloc & b) { michael@0: T* tmp = b.ptr; michael@0: b.ptr = ptr; michael@0: ptr = tmp; michael@0: } michael@0: michael@0: T* release() { michael@0: T* tmp = ptr; michael@0: ptr = 0; michael@0: return tmp; michael@0: } michael@0: michael@0: private: michael@0: michael@0: // no reason to use these: each scoped_ptr_malloc should have its own object michael@0: template michael@0: bool operator==(scoped_ptr_malloc const& p) const; michael@0: template michael@0: bool operator!=(scoped_ptr_malloc const& p) const; michael@0: michael@0: static FreeProc const free_; michael@0: }; michael@0: michael@0: template michael@0: FP const scoped_ptr_malloc::free_ = FP(); michael@0: michael@0: template inline michael@0: void swap(scoped_ptr_malloc& a, scoped_ptr_malloc& b) { michael@0: a.swap(b); michael@0: } michael@0: michael@0: template inline michael@0: bool operator==(T* p, const scoped_ptr_malloc& b) { michael@0: return p == b.get(); michael@0: } michael@0: michael@0: template inline michael@0: bool operator!=(T* p, const scoped_ptr_malloc& b) { michael@0: return p != b.get(); michael@0: } michael@0: michael@0: michael@0: //////////////////////////////////////////////////////////////// michael@0: // Module michael@0: // michael@0: michael@0: // A Module represents the contents of a module, and supports methods michael@0: // for adding information produced by parsing STABS or DWARF data michael@0: // --- possibly both from the same file --- and then writing out the michael@0: // unified contents as a Breakpad-format symbol file. michael@0: class Module { michael@0: public: michael@0: // The type of addresses and sizes in a symbol table. michael@0: typedef uint64_t Address; michael@0: michael@0: // Representation of an expression. This can either be a postfix michael@0: // expression, in which case it is stored as a string, or a simple michael@0: // expression of the form (identifier + imm) or *(identifier + imm). michael@0: // It can also be invalid (denoting "no value"). michael@0: enum ExprHow { michael@0: kExprInvalid = 1, michael@0: kExprPostfix, michael@0: kExprSimple, michael@0: kExprSimpleMem michael@0: }; michael@0: michael@0: struct Expr { michael@0: // Construct a simple-form expression michael@0: Expr(const UniqueString* ident, long offset, bool deref) { michael@0: if (ident == ustr__empty()) { michael@0: Expr(); michael@0: } else { michael@0: postfix_ = ""; michael@0: ident_ = ident; michael@0: offset_ = offset; michael@0: how_ = deref ? kExprSimpleMem : kExprSimple; michael@0: } michael@0: } michael@0: michael@0: // Construct an invalid expression michael@0: Expr() { michael@0: postfix_ = ""; michael@0: ident_ = nullptr; michael@0: offset_ = 0; michael@0: how_ = kExprInvalid; michael@0: } michael@0: michael@0: // Return the postfix expression string, either directly, michael@0: // if this is a postfix expression, or by synthesising it michael@0: // for a simple expression. michael@0: std::string getExprPostfix() const { michael@0: switch (how_) { michael@0: case kExprPostfix: michael@0: return postfix_; michael@0: case kExprSimple: michael@0: case kExprSimpleMem: { michael@0: char buf[40]; michael@0: sprintf(buf, " %ld %c%s", labs(offset_), offset_ < 0 ? '-' : '+', michael@0: how_ == kExprSimple ? "" : " ^"); michael@0: return std::string(FromUniqueString(ident_)) + std::string(buf); michael@0: } michael@0: case kExprInvalid: michael@0: default: michael@0: MOZ_ASSERT(0 && "getExprPostfix: invalid Module::Expr type"); michael@0: return "Expr::genExprPostfix: kExprInvalid"; michael@0: } michael@0: } michael@0: michael@0: // The identifier that gives the starting value for simple expressions. michael@0: const UniqueString* ident_; michael@0: // The offset to add for simple expressions. michael@0: long offset_; michael@0: // The Postfix expression string to evaluate for non-simple expressions. michael@0: std::string postfix_; michael@0: // The operation expressed by this expression. michael@0: ExprHow how_; michael@0: }; michael@0: michael@0: // A map from register names to expressions that recover michael@0: // their values. This can represent a complete set of rules to michael@0: // follow at some address, or a set of changes to be applied to an michael@0: // extant set of rules. michael@0: // NOTE! there are two completely different types called RuleMap. This michael@0: // is one of them. michael@0: typedef std::map RuleMap; michael@0: michael@0: // A map from addresses to RuleMaps, representing changes that take michael@0: // effect at given addresses. michael@0: typedef std::map RuleChangeMap; michael@0: michael@0: // A range of 'STACK CFI' stack walking information. An instance of michael@0: // this structure corresponds to a 'STACK CFI INIT' record and the michael@0: // subsequent 'STACK CFI' records that fall within its range. michael@0: struct StackFrameEntry { michael@0: // The starting address and number of bytes of machine code this michael@0: // entry covers. michael@0: Address address, size; michael@0: michael@0: // The initial register recovery rules, in force at the starting michael@0: // address. michael@0: RuleMap initial_rules; michael@0: michael@0: // A map from addresses to rule changes. To find the rules in michael@0: // force at a given address, start with initial_rules, and then michael@0: // apply the changes given in this map for all addresses up to and michael@0: // including the address you're interested in. michael@0: RuleChangeMap rule_changes; michael@0: }; michael@0: michael@0: // Create a new module with the given name, operating system, michael@0: // architecture, and ID string. michael@0: Module(const std::string &name, const std::string &os, michael@0: const std::string &architecture, const std::string &id); michael@0: ~Module(); michael@0: michael@0: private: michael@0: michael@0: // Module header entries. michael@0: std::string name_, os_, architecture_, id_; michael@0: }; michael@0: michael@0: michael@0: } // namespace lul michael@0: michael@0: #endif // LulCommonExt_h