1 // Copyright 2007 Google LLC 2 // 3 // Redistribution and use in source and binary forms, with or without 4 // modification, are permitted provided that the following conditions are 5 // met: 6 // 7 // * Redistributions of source code must retain the above copyright 8 // notice, this list of conditions and the following disclaimer. 9 // * Redistributions in binary form must reproduce the above 10 // copyright notice, this list of conditions and the following disclaimer 11 // in the documentation and/or other materials provided with the 12 // distribution. 13 // * Neither the name of Google LLC nor the names of its 14 // contributors may be used to endorse or promote products derived from 15 // this software without specific prior written permission. 16 // 17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 29 // dynamic_images.h 30 // 31 // Implements most of the function of the dyld API, but allowing an 32 // arbitrary task to be introspected, unlike the dyld API which 33 // only allows operation on the current task. The current implementation 34 // is limited to use by 32-bit tasks. 35 36 #ifndef CLIENT_MAC_HANDLER_DYNAMIC_IMAGES_H__ 37 #define CLIENT_MAC_HANDLER_DYNAMIC_IMAGES_H__ 38 39 #include <mach/mach.h> 40 #include <mach-o/dyld.h> 41 #include <mach-o/loader.h> 42 #include <sys/types.h> 43 44 #include <string> 45 #include <vector> 46 47 #include "mach_vm_compat.h" 48 49 namespace google_breakpad { 50 51 using std::string; 52 using std::vector; 53 54 //============================================================================== 55 // The memory layout of this struct matches the dyld_image_info struct 56 // defined in "dyld_gdb.h" in the darwin source. 57 typedef struct dyld_image_info32 { 58 uint32_t load_address_; // struct mach_header* 59 uint32_t file_path_; // char* 60 uint32_t file_mod_date_; 61 } dyld_image_info32; 62 63 typedef struct dyld_image_info64 { 64 uint64_t load_address_; // struct mach_header* 65 uint64_t file_path_; // char* 66 uint64_t file_mod_date_; 67 } dyld_image_info64; 68 69 //============================================================================== 70 // This is as defined in "dyld_gdb.h" in the darwin source. 71 // _dyld_all_image_infos (in dyld) is a structure of this type 72 // which will be used to determine which dynamic code has been loaded. 73 typedef struct dyld_all_image_infos32 { 74 uint32_t version; // == 1 in Mac OS X 10.4 75 uint32_t infoArrayCount; 76 uint32_t infoArray; // const struct dyld_image_info* 77 uint32_t notification; 78 bool processDetachedFromSharedRegion; 79 } dyld_all_image_infos32; 80 81 typedef struct dyld_all_image_infos64 { 82 uint32_t version; // == 1 in Mac OS X 10.4 83 uint32_t infoArrayCount; 84 uint64_t infoArray; // const struct dyld_image_info* 85 uint64_t notification; 86 bool processDetachedFromSharedRegion; 87 } dyld_all_image_infos64; 88 89 // some typedefs to isolate 64/32 bit differences 90 #ifdef __LP64__ 91 typedef mach_header_64 breakpad_mach_header; 92 typedef segment_command_64 breakpad_mach_segment_command; 93 #else 94 typedef mach_header breakpad_mach_header; 95 typedef segment_command breakpad_mach_segment_command; 96 #endif 97 98 // Helper functions to deal with 32-bit/64-bit Mach-O differences. 99 class DynamicImage; 100 template<typename MachBits> 101 bool FindTextSection(DynamicImage& image); 102 103 template<typename MachBits> 104 uint32_t GetFileTypeFromHeader(DynamicImage& image); 105 106 //============================================================================== 107 // Represents a single dynamically loaded mach-o image 108 class DynamicImage { 109 public: DynamicImage(uint8_t * header,size_t header_size,uint64_t load_address,string file_path,uintptr_t image_mod_date,mach_port_t task,cpu_type_t cpu_type)110 DynamicImage(uint8_t* header, // data is copied 111 size_t header_size, // includes load commands 112 uint64_t load_address, 113 string file_path, 114 uintptr_t image_mod_date, 115 mach_port_t task, 116 cpu_type_t cpu_type) 117 : header_(header, header + header_size), 118 header_size_(header_size), 119 load_address_(load_address), 120 vmaddr_(0), 121 vmsize_(0), 122 slide_(0), 123 version_(0), 124 file_path_(file_path), 125 file_mod_date_(image_mod_date), 126 task_(task), 127 cpu_type_(cpu_type) { 128 CalculateMemoryAndVersionInfo(); 129 } 130 131 // Size of mach_header plus load commands GetHeaderSize()132 size_t GetHeaderSize() const {return header_.size();} 133 134 // Full path to mach-o binary GetFilePath()135 string GetFilePath() {return file_path_;} 136 GetModDate()137 uint64_t GetModDate() const {return file_mod_date_;} 138 139 // Actual address where the image was loaded GetLoadAddress()140 uint64_t GetLoadAddress() const {return load_address_;} 141 142 // Address where the image should be loaded GetVMAddr()143 mach_vm_address_t GetVMAddr() const {return vmaddr_;} 144 145 // Difference between GetLoadAddress() and GetVMAddr() GetVMAddrSlide()146 ptrdiff_t GetVMAddrSlide() const {return slide_;} 147 148 // Size of the image GetVMSize()149 mach_vm_size_t GetVMSize() const {return vmsize_;} 150 151 // Task owning this loaded image GetTask()152 mach_port_t GetTask() {return task_;} 153 154 // CPU type of the task GetCPUType()155 cpu_type_t GetCPUType() {return cpu_type_;} 156 157 // filetype from the Mach-O header. 158 uint32_t GetFileType(); 159 160 // Return true if the task is a 64-bit architecture. Is64Bit()161 bool Is64Bit() { return (GetCPUType() & CPU_ARCH_ABI64) == CPU_ARCH_ABI64; } 162 GetVersion()163 uint32_t GetVersion() {return version_;} 164 // For sorting 165 bool operator<(const DynamicImage& inInfo) { 166 return GetLoadAddress() < inInfo.GetLoadAddress(); 167 } 168 169 // Sanity checking IsValid()170 bool IsValid() {return GetVMSize() != 0;} 171 172 private: 173 DynamicImage(const DynamicImage&); 174 DynamicImage& operator=(const DynamicImage&); 175 176 friend class DynamicImages; 177 template<typename MachBits> 178 friend bool FindTextSection(DynamicImage& image); 179 template<typename MachBits> 180 friend uint32_t GetFileTypeFromHeader(DynamicImage& image); 181 182 // Initializes vmaddr_, vmsize_, and slide_ 183 void CalculateMemoryAndVersionInfo(); 184 185 const vector<uint8_t> header_; // our local copy of the header 186 size_t header_size_; // mach_header plus load commands 187 uint64_t load_address_; // base address image is mapped into 188 mach_vm_address_t vmaddr_; 189 mach_vm_size_t vmsize_; 190 ptrdiff_t slide_; 191 uint32_t version_; // Dylib version 192 string file_path_; // path dyld used to load the image 193 uintptr_t file_mod_date_; // time_t of image file 194 195 mach_port_t task_; 196 cpu_type_t cpu_type_; // CPU type of task_ 197 }; 198 199 //============================================================================== 200 // DynamicImageRef is just a simple wrapper for a pointer to 201 // DynamicImage. The reason we use it instead of a simple typedef is so 202 // that we can use stl::sort() on a vector of DynamicImageRefs 203 // and simple class pointers can't implement operator<(). 204 // 205 class DynamicImageRef { 206 public: DynamicImageRef(DynamicImage * inP)207 explicit DynamicImageRef(DynamicImage* inP) : p(inP) {} 208 // The copy constructor is required by STL 209 DynamicImageRef(const DynamicImageRef& inRef) = default; 210 DynamicImageRef& operator=(const DynamicImageRef& inRef) = default; 211 212 bool operator<(const DynamicImageRef& inRef) const { 213 return (*const_cast<DynamicImageRef*>(this)->p) 214 < (*const_cast<DynamicImageRef&>(inRef).p); 215 } 216 217 bool operator==(const DynamicImageRef& inInfo) const { 218 return (*const_cast<DynamicImageRef*>(this)->p).GetLoadAddress() == 219 (*const_cast<DynamicImageRef&>(inInfo)).GetLoadAddress(); 220 } 221 222 // Be just like DynamicImage* 223 DynamicImage* operator->() {return p;} 224 operator DynamicImage*() {return p;} 225 226 private: 227 DynamicImage* p; 228 }; 229 230 // Helper function to deal with 32-bit/64-bit Mach-O differences. 231 class DynamicImages; 232 template<typename MachBits> 233 void ReadImageInfo(DynamicImages& images, uint64_t image_list_address); 234 235 //============================================================================== 236 // An object of type DynamicImages may be created to allow introspection of 237 // an arbitrary task's dynamically loaded mach-o binaries. This makes the 238 // assumption that the current task has send rights to the target task. 239 class DynamicImages { 240 public: 241 explicit DynamicImages(mach_port_t task); 242 ~DynamicImages()243 ~DynamicImages() { 244 for (int i = 0; i < GetImageCount(); ++i) { 245 delete image_list_[i]; 246 } 247 } 248 249 // Returns the number of dynamically loaded mach-o images. GetImageCount()250 int GetImageCount() const {return static_cast<int>(image_list_.size());} 251 252 // Returns an individual image. GetImage(int i)253 DynamicImage* GetImage(int i) { 254 if (i < (int)image_list_.size()) { 255 return image_list_[i]; 256 } 257 return NULL; 258 } 259 260 // Returns the image corresponding to the main executable. 261 DynamicImage* GetExecutableImage(); 262 int GetExecutableImageIndex(); 263 264 // Returns the task which we're looking at. GetTask()265 mach_port_t GetTask() const {return task_;} 266 267 // CPU type of the task GetCPUType()268 cpu_type_t GetCPUType() {return cpu_type_;} 269 270 // Return true if the task is a 64-bit architecture. Is64Bit()271 bool Is64Bit() { return (GetCPUType() & CPU_ARCH_ABI64) == CPU_ARCH_ABI64; } 272 273 // Determine the CPU type of the task being dumped. 274 static cpu_type_t DetermineTaskCPUType(task_t task); 275 276 // Get the native CPU type of this task. GetNativeCPUType()277 static cpu_type_t GetNativeCPUType() { 278 #if defined(__i386__) 279 return CPU_TYPE_I386; 280 #elif defined(__x86_64__) 281 return CPU_TYPE_X86_64; 282 #elif defined(__ppc__) 283 return CPU_TYPE_POWERPC; 284 #elif defined(__ppc64__) 285 return CPU_TYPE_POWERPC64; 286 #elif defined(__arm__) 287 return CPU_TYPE_ARM; 288 #elif defined(__aarch64__) 289 return CPU_TYPE_ARM64; 290 #else 291 #error "GetNativeCPUType not implemented for this architecture" 292 #endif 293 } 294 295 private: 296 template<typename MachBits> 297 friend void ReadImageInfo(DynamicImages& images, uint64_t image_list_address); 298 IsOurTask()299 bool IsOurTask() {return task_ == mach_task_self();} 300 301 // Initialization 302 void ReadImageInfoForTask(); 303 uint64_t GetDyldAllImageInfosPointer(); 304 305 mach_port_t task_; 306 cpu_type_t cpu_type_; // CPU type of task_ 307 vector<DynamicImageRef> image_list_; 308 }; 309 310 // Fill bytes with the contents of memory at a particular 311 // location in another task. 312 kern_return_t ReadTaskMemory(task_port_t target_task, 313 const uint64_t address, 314 size_t length, 315 vector<uint8_t>& bytes); 316 317 } // namespace google_breakpad 318 319 #endif // CLIENT_MAC_HANDLER_DYNAMIC_IMAGES_H__ 320