1 // Copyright (c) 2007, Google Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 //     * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 //     * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 //     * Neither the name of Google Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 
30 //  dynamic_images.h
31 //
32 //    Implements most of the function of the dyld API, but allowing an
33 //    arbitrary task to be introspected, unlike the dyld API which
34 //    only allows operation on the current task.  The current implementation
35 //    is limited to use by 32-bit tasks.
36 
37 #ifndef CLIENT_MAC_HANDLER_DYNAMIC_IMAGES_H__
38 #define CLIENT_MAC_HANDLER_DYNAMIC_IMAGES_H__
39 
40 #include <mach/mach.h>
41 #include <mach-o/dyld.h>
42 #include <mach-o/loader.h>
43 #include <sys/types.h>
44 
45 #include <string>
46 #include <vector>
47 
48 #include "mach_vm_compat.h"
49 
50 namespace google_breakpad {
51 
52 using std::string;
53 using std::vector;
54 
55 //==============================================================================
56 // The memory layout of this struct matches the dyld_image_info struct
57 // defined in "dyld_gdb.h" in the darwin source.
58 typedef struct dyld_image_info32 {
59   uint32_t                   load_address_;  // struct mach_header*
60   uint32_t                   file_path_;     // char*
61   uint32_t                   file_mod_date_;
62 } dyld_image_info32;
63 
64 typedef struct dyld_image_info64 {
65   uint64_t                   load_address_;  // struct mach_header*
66   uint64_t                   file_path_;     // char*
67   uint64_t                   file_mod_date_;
68 } dyld_image_info64;
69 
70 //==============================================================================
71 // This is as defined in "dyld_gdb.h" in the darwin source.
72 // _dyld_all_image_infos (in dyld) is a structure of this type
73 // which will be used to determine which dynamic code has been loaded.
74 typedef struct dyld_all_image_infos32 {
75   uint32_t                      version;  // == 1 in Mac OS X 10.4
76   uint32_t                      infoArrayCount;
77   uint32_t                      infoArray;  // const struct dyld_image_info*
78   uint32_t                      notification;
79   bool                          processDetachedFromSharedRegion;
80 } dyld_all_image_infos32;
81 
82 typedef struct dyld_all_image_infos64 {
83   uint32_t                      version;  // == 1 in Mac OS X 10.4
84   uint32_t                      infoArrayCount;
85   uint64_t                      infoArray;  // const struct dyld_image_info*
86   uint64_t                      notification;
87   bool                          processDetachedFromSharedRegion;
88 } dyld_all_image_infos64;
89 
90 // some typedefs to isolate 64/32 bit differences
91 #ifdef __LP64__
92 typedef mach_header_64 breakpad_mach_header;
93 typedef segment_command_64 breakpad_mach_segment_command;
94 #else
95 typedef mach_header breakpad_mach_header;
96 typedef segment_command breakpad_mach_segment_command;
97 #endif
98 
99 // Helper functions to deal with 32-bit/64-bit Mach-O differences.
100 class DynamicImage;
101 template<typename MachBits>
102 bool FindTextSection(DynamicImage& image);
103 
104 template<typename MachBits>
105 uint32_t GetFileTypeFromHeader(DynamicImage& image);
106 
107 //==============================================================================
108 // Represents a single dynamically loaded mach-o image
109 class DynamicImage {
110  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)111   DynamicImage(uint8_t *header,     // data is copied
112                size_t header_size,  // includes load commands
113                uint64_t load_address,
114                string file_path,
115                uintptr_t image_mod_date,
116                mach_port_t task,
117                cpu_type_t cpu_type)
118     : header_(header, header + header_size),
119       header_size_(header_size),
120       load_address_(load_address),
121       vmaddr_(0),
122       vmsize_(0),
123       slide_(0),
124       version_(0),
125       file_path_(file_path),
126       file_mod_date_(image_mod_date),
127       task_(task),
128       cpu_type_(cpu_type) {
129     CalculateMemoryAndVersionInfo();
130   }
131 
132   // Size of mach_header plus load commands
GetHeaderSize()133   size_t GetHeaderSize() const {return header_.size();}
134 
135   // Full path to mach-o binary
GetFilePath()136   string GetFilePath() {return file_path_;}
137 
GetModDate()138   uint64_t GetModDate() const {return file_mod_date_;}
139 
140   // Actual address where the image was loaded
GetLoadAddress()141   uint64_t GetLoadAddress() const {return load_address_;}
142 
143   // Address where the image should be loaded
GetVMAddr()144   mach_vm_address_t GetVMAddr() const {return vmaddr_;}
145 
146   // Difference between GetLoadAddress() and GetVMAddr()
GetVMAddrSlide()147   ptrdiff_t GetVMAddrSlide() const {return slide_;}
148 
149   // Size of the image
GetVMSize()150   mach_vm_size_t GetVMSize() const {return vmsize_;}
151 
152   // Task owning this loaded image
GetTask()153   mach_port_t GetTask() {return task_;}
154 
155   // CPU type of the task
GetCPUType()156   cpu_type_t GetCPUType() {return cpu_type_;}
157 
158   // filetype from the Mach-O header.
159   uint32_t GetFileType();
160 
161   // Return true if the task is a 64-bit architecture.
Is64Bit()162   bool Is64Bit() { return (GetCPUType() & CPU_ARCH_ABI64) == CPU_ARCH_ABI64; }
163 
GetVersion()164   uint32_t GetVersion() {return version_;}
165   // For sorting
166   bool operator<(const DynamicImage &inInfo) {
167     return GetLoadAddress() < inInfo.GetLoadAddress();
168   }
169 
170   // Sanity checking
IsValid()171   bool IsValid() {return GetVMSize() != 0;}
172 
173  private:
174   DynamicImage(const DynamicImage &);
175   DynamicImage &operator=(const DynamicImage &);
176 
177   friend class DynamicImages;
178   template<typename MachBits>
179   friend bool FindTextSection(DynamicImage& image);
180   template<typename MachBits>
181   friend uint32_t GetFileTypeFromHeader(DynamicImage& image);
182 
183   // Initializes vmaddr_, vmsize_, and slide_
184   void CalculateMemoryAndVersionInfo();
185 
186   const vector<uint8_t>   header_;        // our local copy of the header
187   size_t                  header_size_;    // mach_header plus load commands
188   uint64_t                load_address_;   // base address image is mapped into
189   mach_vm_address_t       vmaddr_;
190   mach_vm_size_t          vmsize_;
191   ptrdiff_t               slide_;
192   uint32_t                version_;        // Dylib version
193   string                  file_path_;     // path dyld used to load the image
194   uintptr_t               file_mod_date_;  // time_t of image file
195 
196   mach_port_t             task_;
197   cpu_type_t              cpu_type_;        // CPU type of task_
198 };
199 
200 //==============================================================================
201 // DynamicImageRef is just a simple wrapper for a pointer to
202 // DynamicImage.  The reason we use it instead of a simple typedef is so
203 // that we can use stl::sort() on a vector of DynamicImageRefs
204 // and simple class pointers can't implement operator<().
205 //
206 class DynamicImageRef {
207  public:
DynamicImageRef(DynamicImage * inP)208   explicit DynamicImageRef(DynamicImage *inP) : p(inP) {}
209   // The copy constructor is required by STL
DynamicImageRef(const DynamicImageRef & inRef)210   DynamicImageRef(const DynamicImageRef &inRef) : p(inRef.p) {}
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