Planeshift

dynamic_images.h

Go to the documentation of this file.
00001 // Copyright (c) 2007, Google Inc.
00002 // All rights reserved.
00003 //
00004 // Redistribution and use in source and binary forms, with or without
00005 // modification, are permitted provided that the following conditions are
00006 // met:
00007 //
00008 //     * Redistributions of source code must retain the above copyright
00009 // notice, this list of conditions and the following disclaimer.
00010 //     * Redistributions in binary form must reproduce the above
00011 // copyright notice, this list of conditions and the following disclaimer
00012 // in the documentation and/or other materials provided with the
00013 // distribution.
00014 //     * Neither the name of Google Inc. nor the names of its
00015 // contributors may be used to endorse or promote products derived from
00016 // this software without specific prior written permission.
00017 //
00018 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00019 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00020 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
00021 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
00022 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00023 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00024 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00025 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00026 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00027 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00028 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029 
00030 //  dynamic_images.h
00031 //
00032 //    Implements most of the function of the dyld API, but allowing an
00033 //    arbitrary task to be introspected, unlike the dyld API which
00034 //    only allows operation on the current task.  The current implementation
00035 //    is limited to use by 32-bit tasks.
00036 
00037 #ifndef CLIENT_MAC_HANDLER_DYNAMIC_IMAGES_H__
00038 #define CLIENT_MAC_HANDLER_DYNAMIC_IMAGES_H__
00039 
00040 #include <mach/mach.h>
00041 #include <mach-o/dyld.h>
00042 #include <mach-o/loader.h>
00043 #include <sys/types.h>
00044 
00045 #include <string>
00046 #include <vector>
00047 
00048 #include "mach_vm_compat.h"
00049 
00050 namespace google_breakpad {
00051 
00052 using std::string;
00053 using std::vector;
00054 
00055 //==============================================================================
00056 // The memory layout of this struct matches the dyld_image_info struct
00057 // defined in "dyld_gdb.h" in the darwin source.
00058 typedef struct dyld_image_info32 {
00059   uint32_t                   load_address_;  // struct mach_header*
00060   uint32_t                   file_path_;     // char*
00061   uint32_t                   file_mod_date_;
00062 } dyld_image_info32;
00063 
00064 typedef struct dyld_image_info64 {
00065   uint64_t                   load_address_;  // struct mach_header*
00066   uint64_t                   file_path_;     // char*
00067   uint64_t                   file_mod_date_;
00068 } dyld_image_info64;
00069 
00070 //==============================================================================
00071 // This is as defined in "dyld_gdb.h" in the darwin source.
00072 // _dyld_all_image_infos (in dyld) is a structure of this type
00073 // which will be used to determine which dynamic code has been loaded.
00074 typedef struct dyld_all_image_infos32 {
00075   uint32_t                      version;  // == 1 in Mac OS X 10.4
00076   uint32_t                      infoArrayCount;
00077   uint32_t                      infoArray;  // const struct dyld_image_info*
00078   uint32_t                      notification;
00079   bool                          processDetachedFromSharedRegion;
00080 } dyld_all_image_infos32;
00081 
00082 typedef struct dyld_all_image_infos64 {
00083   uint32_t                      version;  // == 1 in Mac OS X 10.4
00084   uint32_t                      infoArrayCount;
00085   uint64_t                      infoArray;  // const struct dyld_image_info*
00086   uint64_t                      notification;
00087   bool                          processDetachedFromSharedRegion;
00088 } dyld_all_image_infos64;
00089 
00090 // some typedefs to isolate 64/32 bit differences
00091 #ifdef __LP64__
00092 typedef mach_header_64 breakpad_mach_header;
00093 typedef segment_command_64 breakpad_mach_segment_command;
00094 #else
00095 typedef mach_header breakpad_mach_header;
00096 typedef segment_command breakpad_mach_segment_command;
00097 #endif
00098 
00099 // Helper functions to deal with 32-bit/64-bit Mach-O differences.
00100 class DynamicImage;
00101 template<typename MachBits>
00102 bool FindTextSection(DynamicImage& image);
00103 
00104 template<typename MachBits>
00105 uint32_t GetFileTypeFromHeader(DynamicImage& image);
00106 
00107 //==============================================================================
00108 // Represents a single dynamically loaded mach-o image
00109 class DynamicImage {
00110  public:
00111   DynamicImage(uint8_t *header,     // data is copied
00112                size_t header_size,  // includes load commands
00113                uint64_t load_address,
00114                string file_path,
00115                uintptr_t image_mod_date,
00116                mach_port_t task,
00117                cpu_type_t cpu_type)
00118     : header_(header, header + header_size),
00119       header_size_(header_size),
00120       load_address_(load_address),
00121       vmaddr_(0),
00122       vmsize_(0),
00123       slide_(0),
00124       version_(0),
00125       file_path_(file_path),
00126       file_mod_date_(image_mod_date),
00127       task_(task),
00128       cpu_type_(cpu_type) {
00129     CalculateMemoryAndVersionInfo();
00130   }
00131 
00132   // Size of mach_header plus load commands
00133   size_t GetHeaderSize() const {return header_.size();}
00134 
00135   // Full path to mach-o binary
00136   string GetFilePath() {return file_path_;}
00137 
00138   uint64_t GetModDate() const {return file_mod_date_;}
00139 
00140   // Actual address where the image was loaded
00141   uint64_t GetLoadAddress() const {return load_address_;}
00142 
00143   // Address where the image should be loaded
00144   mach_vm_address_t GetVMAddr() const {return vmaddr_;}
00145 
00146   // Difference between GetLoadAddress() and GetVMAddr()
00147   ptrdiff_t GetVMAddrSlide() const {return slide_;}
00148 
00149   // Size of the image
00150   mach_vm_size_t GetVMSize() const {return vmsize_;}
00151 
00152   // Task owning this loaded image
00153   mach_port_t GetTask() {return task_;}
00154 
00155   // CPU type of the task
00156   cpu_type_t GetCPUType() {return cpu_type_;}
00157 
00158   // filetype from the Mach-O header.
00159   uint32_t GetFileType();
00160 
00161   // Return true if the task is a 64-bit architecture.
00162   bool Is64Bit() { return (GetCPUType() & CPU_ARCH_ABI64) == CPU_ARCH_ABI64; }
00163 
00164   uint32_t GetVersion() {return version_;}
00165   // For sorting
00166   bool operator<(const DynamicImage &inInfo) {
00167     return GetLoadAddress() < inInfo.GetLoadAddress();
00168   }
00169 
00170   // Sanity checking
00171   bool IsValid() {return GetVMSize() != 0;}
00172 
00173  private:
00174   DynamicImage(const DynamicImage &);
00175   DynamicImage &operator=(const DynamicImage &);
00176 
00177   friend class DynamicImages;
00178   template<typename MachBits>
00179   friend bool FindTextSection(DynamicImage& image);
00180   template<typename MachBits>
00181   friend uint32_t GetFileTypeFromHeader(DynamicImage& image);
00182 
00183   // Initializes vmaddr_, vmsize_, and slide_
00184   void CalculateMemoryAndVersionInfo();
00185 
00186   const vector<uint8_t>   header_;        // our local copy of the header
00187   size_t                  header_size_;    // mach_header plus load commands
00188   uint64_t                load_address_;   // base address image is mapped into
00189   mach_vm_address_t       vmaddr_;
00190   mach_vm_size_t          vmsize_;
00191   ptrdiff_t               slide_;
00192   uint32_t                version_;        // Dylib version
00193   string                  file_path_;     // path dyld used to load the image
00194   uintptr_t               file_mod_date_;  // time_t of image file
00195 
00196   mach_port_t             task_;
00197   cpu_type_t              cpu_type_;        // CPU type of task_
00198 };
00199 
00200 //==============================================================================
00201 // DynamicImageRef is just a simple wrapper for a pointer to
00202 // DynamicImage.  The reason we use it instead of a simple typedef is so
00203 // that we can use stl::sort() on a vector of DynamicImageRefs
00204 // and simple class pointers can't implement operator<().
00205 //
00206 class DynamicImageRef {
00207  public:
00208   explicit DynamicImageRef(DynamicImage *inP) : p(inP) {}
00209   // The copy constructor is required by STL
00210   DynamicImageRef(const DynamicImageRef &inRef) : p(inRef.p) {}
00211 
00212   bool operator<(const DynamicImageRef &inRef) const {
00213     return (*const_cast<DynamicImageRef*>(this)->p)
00214       < (*const_cast<DynamicImageRef&>(inRef).p);
00215   }
00216 
00217   bool operator==(const DynamicImageRef &inInfo) const {
00218     return (*const_cast<DynamicImageRef*>(this)->p).GetLoadAddress() ==
00219         (*const_cast<DynamicImageRef&>(inInfo)).GetLoadAddress();
00220   }
00221 
00222   // Be just like DynamicImage*
00223   DynamicImage  *operator->() {return p;}
00224   operator DynamicImage*() {return p;}
00225 
00226  private:
00227   DynamicImage  *p;
00228 };
00229 
00230 // Helper function to deal with 32-bit/64-bit Mach-O differences.
00231 class DynamicImages;
00232 template<typename MachBits>
00233 void ReadImageInfo(DynamicImages& images, uint64_t image_list_address);
00234 
00235 //==============================================================================
00236 // An object of type DynamicImages may be created to allow introspection of
00237 // an arbitrary task's dynamically loaded mach-o binaries.  This makes the
00238 // assumption that the current task has send rights to the target task.
00239 class DynamicImages {
00240  public:
00241   explicit DynamicImages(mach_port_t task);
00242 
00243   ~DynamicImages() {
00244     for (int i = 0; i < GetImageCount(); ++i) {
00245       delete image_list_[i];
00246     }
00247   }
00248 
00249   // Returns the number of dynamically loaded mach-o images.
00250   int GetImageCount() const {return static_cast<int>(image_list_.size());}
00251 
00252   // Returns an individual image.
00253   DynamicImage *GetImage(int i) {
00254     if (i < (int)image_list_.size()) {
00255       return image_list_[i];
00256     }
00257     return NULL;
00258   }
00259 
00260   // Returns the image corresponding to the main executable.
00261   DynamicImage *GetExecutableImage();
00262   int GetExecutableImageIndex();
00263 
00264   // Returns the task which we're looking at.
00265   mach_port_t GetTask() const {return task_;}
00266 
00267   // CPU type of the task
00268   cpu_type_t GetCPUType() {return cpu_type_;}
00269 
00270   // Return true if the task is a 64-bit architecture.
00271   bool Is64Bit() { return (GetCPUType() & CPU_ARCH_ABI64) == CPU_ARCH_ABI64; }
00272 
00273   // Determine the CPU type of the task being dumped.
00274   static cpu_type_t DetermineTaskCPUType(task_t task);
00275 
00276   // Get the native CPU type of this task.
00277   static cpu_type_t GetNativeCPUType() {
00278 #if defined(__i386__)
00279     return CPU_TYPE_I386;
00280 #elif defined(__x86_64__)
00281     return CPU_TYPE_X86_64;
00282 #elif defined(__ppc__)
00283     return CPU_TYPE_POWERPC;
00284 #elif defined(__ppc64__)
00285     return CPU_TYPE_POWERPC64;
00286 #elif defined(__arm__)
00287     return CPU_TYPE_ARM;
00288 #else
00289 #error "GetNativeCPUType not implemented for this architecture"
00290 #endif
00291   }
00292 
00293  private:
00294   template<typename MachBits>
00295   friend void ReadImageInfo(DynamicImages& images, uint64_t image_list_address);
00296 
00297   bool IsOurTask() {return task_ == mach_task_self();}
00298 
00299   // Initialization
00300   void ReadImageInfoForTask();
00301   uint64_t GetDyldAllImageInfosPointer();
00302 
00303   mach_port_t              task_;
00304   cpu_type_t               cpu_type_;  // CPU type of task_
00305   vector<DynamicImageRef>  image_list_;
00306 };
00307 
00308 // Fill bytes with the contents of memory at a particular
00309 // location in another task.
00310 kern_return_t ReadTaskMemory(task_port_t target_task,
00311                              const uint64_t address,
00312                              size_t length,
00313                              vector<uint8_t> &bytes);
00314 
00315 }   // namespace google_breakpad
00316 
00317 #endif // CLIENT_MAC_HANDLER_DYNAMIC_IMAGES_H__