michael@0: // Copyright (c) 2007, 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: // dynamic_images.h michael@0: // michael@0: // Implements most of the function of the dyld API, but allowing an michael@0: // arbitrary task to be introspected, unlike the dyld API which michael@0: // only allows operation on the current task. The current implementation michael@0: // is limited to use by 32-bit tasks. michael@0: michael@0: #ifndef CLIENT_MAC_HANDLER_DYNAMIC_IMAGES_H__ michael@0: #define CLIENT_MAC_HANDLER_DYNAMIC_IMAGES_H__ michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #include michael@0: #include michael@0: michael@0: #include "mach_vm_compat.h" michael@0: michael@0: namespace google_breakpad { michael@0: michael@0: using std::string; michael@0: using std::vector; michael@0: michael@0: //============================================================================== michael@0: // The memory layout of this struct matches the dyld_image_info struct michael@0: // defined in "dyld_gdb.h" in the darwin source. michael@0: typedef struct dyld_image_info32 { michael@0: uint32_t load_address_; // struct mach_header* michael@0: uint32_t file_path_; // char* michael@0: uint32_t file_mod_date_; michael@0: } dyld_image_info32; michael@0: michael@0: typedef struct dyld_image_info64 { michael@0: uint64_t load_address_; // struct mach_header* michael@0: uint64_t file_path_; // char* michael@0: uint64_t file_mod_date_; michael@0: } dyld_image_info64; michael@0: michael@0: //============================================================================== michael@0: // This is as defined in "dyld_gdb.h" in the darwin source. michael@0: // _dyld_all_image_infos (in dyld) is a structure of this type michael@0: // which will be used to determine which dynamic code has been loaded. michael@0: typedef struct dyld_all_image_infos32 { michael@0: uint32_t version; // == 1 in Mac OS X 10.4 michael@0: uint32_t infoArrayCount; michael@0: uint32_t infoArray; // const struct dyld_image_info* michael@0: uint32_t notification; michael@0: bool processDetachedFromSharedRegion; michael@0: } dyld_all_image_infos32; michael@0: michael@0: typedef struct dyld_all_image_infos64 { michael@0: uint32_t version; // == 1 in Mac OS X 10.4 michael@0: uint32_t infoArrayCount; michael@0: uint64_t infoArray; // const struct dyld_image_info* michael@0: uint64_t notification; michael@0: bool processDetachedFromSharedRegion; michael@0: } dyld_all_image_infos64; michael@0: michael@0: // some typedefs to isolate 64/32 bit differences michael@0: #ifdef __LP64__ michael@0: typedef mach_header_64 breakpad_mach_header; michael@0: typedef segment_command_64 breakpad_mach_segment_command; michael@0: #else michael@0: typedef mach_header breakpad_mach_header; michael@0: typedef segment_command breakpad_mach_segment_command; michael@0: #endif michael@0: michael@0: // Helper functions to deal with 32-bit/64-bit Mach-O differences. michael@0: class DynamicImage; michael@0: template michael@0: bool FindTextSection(DynamicImage& image); michael@0: michael@0: template michael@0: uint32_t GetFileTypeFromHeader(DynamicImage& image); michael@0: michael@0: //============================================================================== michael@0: // Represents a single dynamically loaded mach-o image michael@0: class DynamicImage { michael@0: public: michael@0: DynamicImage(uint8_t *header, // data is copied michael@0: size_t header_size, // includes load commands michael@0: uint64_t load_address, michael@0: string file_path, michael@0: uintptr_t image_mod_date, michael@0: mach_port_t task, michael@0: cpu_type_t cpu_type) michael@0: : header_(header, header + header_size), michael@0: header_size_(header_size), michael@0: load_address_(load_address), michael@0: vmaddr_(0), michael@0: vmsize_(0), michael@0: slide_(0), michael@0: version_(0), michael@0: file_path_(file_path), michael@0: file_mod_date_(image_mod_date), michael@0: task_(task), michael@0: cpu_type_(cpu_type) { michael@0: CalculateMemoryAndVersionInfo(); michael@0: } michael@0: michael@0: // Size of mach_header plus load commands michael@0: size_t GetHeaderSize() const {return header_.size();} michael@0: michael@0: // Full path to mach-o binary michael@0: string GetFilePath() {return file_path_;} michael@0: michael@0: uint64_t GetModDate() const {return file_mod_date_;} michael@0: michael@0: // Actual address where the image was loaded michael@0: uint64_t GetLoadAddress() const {return load_address_;} michael@0: michael@0: // Address where the image should be loaded michael@0: mach_vm_address_t GetVMAddr() const {return vmaddr_;} michael@0: michael@0: // Difference between GetLoadAddress() and GetVMAddr() michael@0: ptrdiff_t GetVMAddrSlide() const {return slide_;} michael@0: michael@0: // Size of the image michael@0: mach_vm_size_t GetVMSize() const {return vmsize_;} michael@0: michael@0: // Task owning this loaded image michael@0: mach_port_t GetTask() {return task_;} michael@0: michael@0: // CPU type of the task michael@0: cpu_type_t GetCPUType() {return cpu_type_;} michael@0: michael@0: // filetype from the Mach-O header. michael@0: uint32_t GetFileType(); michael@0: michael@0: // Return true if the task is a 64-bit architecture. michael@0: bool Is64Bit() { return (GetCPUType() & CPU_ARCH_ABI64) == CPU_ARCH_ABI64; } michael@0: michael@0: uint32_t GetVersion() {return version_;} michael@0: // For sorting michael@0: bool operator<(const DynamicImage &inInfo) { michael@0: return GetLoadAddress() < inInfo.GetLoadAddress(); michael@0: } michael@0: michael@0: // Sanity checking michael@0: bool IsValid() {return GetVMSize() != 0;} michael@0: michael@0: private: michael@0: DynamicImage(const DynamicImage &); michael@0: DynamicImage &operator=(const DynamicImage &); michael@0: michael@0: friend class DynamicImages; michael@0: template michael@0: friend bool FindTextSection(DynamicImage& image); michael@0: template michael@0: friend uint32_t GetFileTypeFromHeader(DynamicImage& image); michael@0: michael@0: // Initializes vmaddr_, vmsize_, and slide_ michael@0: void CalculateMemoryAndVersionInfo(); michael@0: michael@0: const vector header_; // our local copy of the header michael@0: size_t header_size_; // mach_header plus load commands michael@0: uint64_t load_address_; // base address image is mapped into michael@0: mach_vm_address_t vmaddr_; michael@0: mach_vm_size_t vmsize_; michael@0: ptrdiff_t slide_; michael@0: uint32_t version_; // Dylib version michael@0: string file_path_; // path dyld used to load the image michael@0: uintptr_t file_mod_date_; // time_t of image file michael@0: michael@0: mach_port_t task_; michael@0: cpu_type_t cpu_type_; // CPU type of task_ michael@0: }; michael@0: michael@0: //============================================================================== michael@0: // DynamicImageRef is just a simple wrapper for a pointer to michael@0: // DynamicImage. The reason we use it instead of a simple typedef is so michael@0: // that we can use stl::sort() on a vector of DynamicImageRefs michael@0: // and simple class pointers can't implement operator<(). michael@0: // michael@0: class DynamicImageRef { michael@0: public: michael@0: explicit DynamicImageRef(DynamicImage *inP) : p(inP) {} michael@0: // The copy constructor is required by STL michael@0: DynamicImageRef(const DynamicImageRef &inRef) : p(inRef.p) {} michael@0: michael@0: bool operator<(const DynamicImageRef &inRef) const { michael@0: return (*const_cast(this)->p) michael@0: < (*const_cast(inRef).p); michael@0: } michael@0: michael@0: bool operator==(const DynamicImageRef &inInfo) const { michael@0: return (*const_cast(this)->p).GetLoadAddress() == michael@0: (*const_cast(inInfo)).GetLoadAddress(); michael@0: } michael@0: michael@0: // Be just like DynamicImage* michael@0: DynamicImage *operator->() {return p;} michael@0: operator DynamicImage*() {return p;} michael@0: michael@0: private: michael@0: DynamicImage *p; michael@0: }; michael@0: michael@0: // Helper function to deal with 32-bit/64-bit Mach-O differences. michael@0: class DynamicImages; michael@0: template michael@0: void ReadImageInfo(DynamicImages& images, uint64_t image_list_address); michael@0: michael@0: //============================================================================== michael@0: // An object of type DynamicImages may be created to allow introspection of michael@0: // an arbitrary task's dynamically loaded mach-o binaries. This makes the michael@0: // assumption that the current task has send rights to the target task. michael@0: class DynamicImages { michael@0: public: michael@0: explicit DynamicImages(mach_port_t task); michael@0: michael@0: ~DynamicImages() { michael@0: for (int i = 0; i < GetImageCount(); ++i) { michael@0: delete image_list_[i]; michael@0: } michael@0: } michael@0: michael@0: // Returns the number of dynamically loaded mach-o images. michael@0: int GetImageCount() const {return static_cast(image_list_.size());} michael@0: michael@0: // Returns an individual image. michael@0: DynamicImage *GetImage(int i) { michael@0: if (i < (int)image_list_.size()) { michael@0: return image_list_[i]; michael@0: } michael@0: return NULL; michael@0: } michael@0: michael@0: // Returns the image corresponding to the main executable. michael@0: DynamicImage *GetExecutableImage(); michael@0: int GetExecutableImageIndex(); michael@0: michael@0: // Returns the task which we're looking at. michael@0: mach_port_t GetTask() const {return task_;} michael@0: michael@0: // CPU type of the task michael@0: cpu_type_t GetCPUType() {return cpu_type_;} michael@0: michael@0: // Return true if the task is a 64-bit architecture. michael@0: bool Is64Bit() { return (GetCPUType() & CPU_ARCH_ABI64) == CPU_ARCH_ABI64; } michael@0: michael@0: // Determine the CPU type of the task being dumped. michael@0: static cpu_type_t DetermineTaskCPUType(task_t task); michael@0: michael@0: // Get the native CPU type of this task. michael@0: static cpu_type_t GetNativeCPUType() { michael@0: #if defined(__i386__) michael@0: return CPU_TYPE_I386; michael@0: #elif defined(__x86_64__) michael@0: return CPU_TYPE_X86_64; michael@0: #elif defined(__ppc__) michael@0: return CPU_TYPE_POWERPC; michael@0: #elif defined(__ppc64__) michael@0: return CPU_TYPE_POWERPC64; michael@0: #elif defined(__arm__) michael@0: return CPU_TYPE_ARM; michael@0: #else michael@0: #error "GetNativeCPUType not implemented for this architecture" michael@0: #endif michael@0: } michael@0: michael@0: private: michael@0: template michael@0: friend void ReadImageInfo(DynamicImages& images, uint64_t image_list_address); michael@0: michael@0: bool IsOurTask() {return task_ == mach_task_self();} michael@0: michael@0: // Initialization michael@0: void ReadImageInfoForTask(); michael@0: uint64_t GetDyldAllImageInfosPointer(); michael@0: michael@0: mach_port_t task_; michael@0: cpu_type_t cpu_type_; // CPU type of task_ michael@0: vector image_list_; michael@0: }; michael@0: michael@0: // Fill bytes with the contents of memory at a particular michael@0: // location in another task. michael@0: kern_return_t ReadTaskMemory(task_port_t target_task, michael@0: const uint64_t address, michael@0: size_t length, michael@0: vector &bytes); michael@0: michael@0: } // namespace google_breakpad michael@0: michael@0: #endif // CLIENT_MAC_HANDLER_DYNAMIC_IMAGES_H__