| // Copyright (c) 2007, Google Inc. |
| // All rights reserved. |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are |
| // met: |
| // |
| // * Redistributions of source code must retain the above copyright |
| // notice, this list of conditions and the following disclaimer. |
| // * Redistributions in binary form must reproduce the above |
| // copyright notice, this list of conditions and the following disclaimer |
| // in the documentation and/or other materials provided with the |
| // distribution. |
| // * Neither the name of Google Inc. nor the names of its |
| // contributors may be used to endorse or promote products derived from |
| // this software without specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| // dynamic_images.h |
| // |
| // Implements most of the function of the dyld API, but allowing an |
| // arbitrary task to be introspected, unlike the dyld API which |
| // only allows operation on the current task. The current implementation |
| // is limited to use by 32-bit tasks. |
| |
| #ifndef CLIENT_MAC_HANDLER_DYNAMIC_IMAGES_H__ |
| #define CLIENT_MAC_HANDLER_DYNAMIC_IMAGES_H__ |
| |
| #include <mach/mach.h> |
| #include <mach-o/dyld.h> |
| #include <mach-o/loader.h> |
| #include <sys/types.h> |
| |
| #include <string> |
| #include <vector> |
| |
| #include "mach_vm_compat.h" |
| |
| namespace google_breakpad { |
| |
| using std::string; |
| using std::vector; |
| |
| //============================================================================== |
| // The memory layout of this struct matches the dyld_image_info struct |
| // defined in "dyld_gdb.h" in the darwin source. |
| typedef struct dyld_image_info32 { |
| uint32_t load_address_; // struct mach_header* |
| uint32_t file_path_; // char* |
| uint32_t file_mod_date_; |
| } dyld_image_info32; |
| |
| typedef struct dyld_image_info64 { |
| uint64_t load_address_; // struct mach_header* |
| uint64_t file_path_; // char* |
| uint64_t file_mod_date_; |
| } dyld_image_info64; |
| |
| //============================================================================== |
| // This is as defined in "dyld_gdb.h" in the darwin source. |
| // _dyld_all_image_infos (in dyld) is a structure of this type |
| // which will be used to determine which dynamic code has been loaded. |
| typedef struct dyld_all_image_infos32 { |
| uint32_t version; // == 1 in Mac OS X 10.4 |
| uint32_t infoArrayCount; |
| uint32_t infoArray; // const struct dyld_image_info* |
| uint32_t notification; |
| bool processDetachedFromSharedRegion; |
| } dyld_all_image_infos32; |
| |
| typedef struct dyld_all_image_infos64 { |
| uint32_t version; // == 1 in Mac OS X 10.4 |
| uint32_t infoArrayCount; |
| uint64_t infoArray; // const struct dyld_image_info* |
| uint64_t notification; |
| bool processDetachedFromSharedRegion; |
| } dyld_all_image_infos64; |
| |
| // some typedefs to isolate 64/32 bit differences |
| #ifdef __LP64__ |
| typedef mach_header_64 breakpad_mach_header; |
| typedef segment_command_64 breakpad_mach_segment_command; |
| #else |
| typedef mach_header breakpad_mach_header; |
| typedef segment_command breakpad_mach_segment_command; |
| #endif |
| |
| // Helper functions to deal with 32-bit/64-bit Mach-O differences. |
| class DynamicImage; |
| template<typename MachBits> |
| bool FindTextSection(DynamicImage& image); |
| |
| template<typename MachBits> |
| uint32_t GetFileTypeFromHeader(DynamicImage& image); |
| |
| //============================================================================== |
| // Represents a single dynamically loaded mach-o image |
| class DynamicImage { |
| public: |
| DynamicImage(uint8_t *header, // data is copied |
| size_t header_size, // includes load commands |
| uint64_t load_address, |
| string file_path, |
| uintptr_t image_mod_date, |
| mach_port_t task, |
| cpu_type_t cpu_type) |
| : header_(header, header + header_size), |
| header_size_(header_size), |
| load_address_(load_address), |
| vmaddr_(0), |
| vmsize_(0), |
| slide_(0), |
| version_(0), |
| file_path_(file_path), |
| file_mod_date_(image_mod_date), |
| task_(task), |
| cpu_type_(cpu_type) { |
| CalculateMemoryAndVersionInfo(); |
| } |
| |
| // Size of mach_header plus load commands |
| size_t GetHeaderSize() const {return header_.size();} |
| |
| // Full path to mach-o binary |
| string GetFilePath() {return file_path_;} |
| |
| uint64_t GetModDate() const {return file_mod_date_;} |
| |
| // Actual address where the image was loaded |
| uint64_t GetLoadAddress() const {return load_address_;} |
| |
| // Address where the image should be loaded |
| mach_vm_address_t GetVMAddr() const {return vmaddr_;} |
| |
| // Difference between GetLoadAddress() and GetVMAddr() |
| ptrdiff_t GetVMAddrSlide() const {return slide_;} |
| |
| // Size of the image |
| mach_vm_size_t GetVMSize() const {return vmsize_;} |
| |
| // Task owning this loaded image |
| mach_port_t GetTask() {return task_;} |
| |
| // CPU type of the task |
| cpu_type_t GetCPUType() {return cpu_type_;} |
| |
| // filetype from the Mach-O header. |
| uint32_t GetFileType(); |
| |
| // Return true if the task is a 64-bit architecture. |
| bool Is64Bit() { return (GetCPUType() & CPU_ARCH_ABI64) == CPU_ARCH_ABI64; } |
| |
| uint32_t GetVersion() {return version_;} |
| // For sorting |
| bool operator<(const DynamicImage &inInfo) { |
| return GetLoadAddress() < inInfo.GetLoadAddress(); |
| } |
| |
| // Sanity checking |
| bool IsValid() {return GetVMSize() != 0;} |
| |
| private: |
| DynamicImage(const DynamicImage &); |
| DynamicImage &operator=(const DynamicImage &); |
| |
| friend class DynamicImages; |
| template<typename MachBits> |
| friend bool FindTextSection(DynamicImage& image); |
| template<typename MachBits> |
| friend uint32_t GetFileTypeFromHeader(DynamicImage& image); |
| |
| // Initializes vmaddr_, vmsize_, and slide_ |
| void CalculateMemoryAndVersionInfo(); |
| |
| const vector<uint8_t> header_; // our local copy of the header |
| size_t header_size_; // mach_header plus load commands |
| uint64_t load_address_; // base address image is mapped into |
| mach_vm_address_t vmaddr_; |
| mach_vm_size_t vmsize_; |
| ptrdiff_t slide_; |
| uint32_t version_; // Dylib version |
| string file_path_; // path dyld used to load the image |
| uintptr_t file_mod_date_; // time_t of image file |
| |
| mach_port_t task_; |
| cpu_type_t cpu_type_; // CPU type of task_ |
| }; |
| |
| //============================================================================== |
| // DynamicImageRef is just a simple wrapper for a pointer to |
| // DynamicImage. The reason we use it instead of a simple typedef is so |
| // that we can use stl::sort() on a vector of DynamicImageRefs |
| // and simple class pointers can't implement operator<(). |
| // |
| class DynamicImageRef { |
| public: |
| explicit DynamicImageRef(DynamicImage *inP) : p(inP) {} |
| // The copy constructor is required by STL |
| DynamicImageRef(const DynamicImageRef &inRef) : p(inRef.p) {} |
| |
| bool operator<(const DynamicImageRef &inRef) const { |
| return (*const_cast<DynamicImageRef*>(this)->p) |
| < (*const_cast<DynamicImageRef&>(inRef).p); |
| } |
| |
| bool operator==(const DynamicImageRef &inInfo) const { |
| return (*const_cast<DynamicImageRef*>(this)->p).GetLoadAddress() == |
| (*const_cast<DynamicImageRef&>(inInfo)).GetLoadAddress(); |
| } |
| |
| // Be just like DynamicImage* |
| DynamicImage *operator->() {return p;} |
| operator DynamicImage*() {return p;} |
| |
| private: |
| DynamicImage *p; |
| }; |
| |
| // Helper function to deal with 32-bit/64-bit Mach-O differences. |
| class DynamicImages; |
| template<typename MachBits> |
| void ReadImageInfo(DynamicImages& images, uint64_t image_list_address); |
| |
| //============================================================================== |
| // An object of type DynamicImages may be created to allow introspection of |
| // an arbitrary task's dynamically loaded mach-o binaries. This makes the |
| // assumption that the current task has send rights to the target task. |
| class DynamicImages { |
| public: |
| explicit DynamicImages(mach_port_t task); |
| |
| ~DynamicImages() { |
| for (int i = 0; i < GetImageCount(); ++i) { |
| delete image_list_[i]; |
| } |
| } |
| |
| // Returns the number of dynamically loaded mach-o images. |
| int GetImageCount() const {return static_cast<int>(image_list_.size());} |
| |
| // Returns an individual image. |
| DynamicImage *GetImage(int i) { |
| if (i < (int)image_list_.size()) { |
| return image_list_[i]; |
| } |
| return NULL; |
| } |
| |
| // Returns the image corresponding to the main executable. |
| DynamicImage *GetExecutableImage(); |
| int GetExecutableImageIndex(); |
| |
| // Returns the task which we're looking at. |
| mach_port_t GetTask() const {return task_;} |
| |
| // CPU type of the task |
| cpu_type_t GetCPUType() {return cpu_type_;} |
| |
| // Return true if the task is a 64-bit architecture. |
| bool Is64Bit() { return (GetCPUType() & CPU_ARCH_ABI64) == CPU_ARCH_ABI64; } |
| |
| // Determine the CPU type of the task being dumped. |
| static cpu_type_t DetermineTaskCPUType(task_t task); |
| |
| // Get the native CPU type of this task. |
| static cpu_type_t GetNativeCPUType() { |
| #if defined(__i386__) |
| return CPU_TYPE_I386; |
| #elif defined(__x86_64__) |
| return CPU_TYPE_X86_64; |
| #elif defined(__ppc__) |
| return CPU_TYPE_POWERPC; |
| #elif defined(__ppc64__) |
| return CPU_TYPE_POWERPC64; |
| #elif defined(__arm__) |
| return CPU_TYPE_ARM; |
| #elif defined(__aarch64__) |
| return CPU_TYPE_ARM64; |
| #else |
| #error "GetNativeCPUType not implemented for this architecture" |
| #endif |
| } |
| |
| private: |
| template<typename MachBits> |
| friend void ReadImageInfo(DynamicImages& images, uint64_t image_list_address); |
| |
| bool IsOurTask() {return task_ == mach_task_self();} |
| |
| // Initialization |
| void ReadImageInfoForTask(); |
| uint64_t GetDyldAllImageInfosPointer(); |
| |
| mach_port_t task_; |
| cpu_type_t cpu_type_; // CPU type of task_ |
| vector<DynamicImageRef> image_list_; |
| }; |
| |
| // Fill bytes with the contents of memory at a particular |
| // location in another task. |
| kern_return_t ReadTaskMemory(task_port_t target_task, |
| const uint64_t address, |
| size_t length, |
| vector<uint8_t> &bytes); |
| |
| } // namespace google_breakpad |
| |
| #endif // CLIENT_MAC_HANDLER_DYNAMIC_IMAGES_H__ |