Planeshift
dynamic_images.h
Go to the documentation of this file.
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_;
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_;
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;
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;
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
110  public:
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
133  size_t GetHeaderSize() const {return header_.size();}
134 
135  // Full path to mach-o binary
136  string GetFilePath() {return file_path_;}
137 
138  uint64_t GetModDate() const {return file_mod_date_;}
139 
140  // Actual address where the image was loaded
141  uint64_t GetLoadAddress() const {return load_address_;}
142 
143  // Address where the image should be loaded
144  mach_vm_address_t GetVMAddr() const {return vmaddr_;}
145 
146  // Difference between GetLoadAddress() and GetVMAddr()
147  ptrdiff_t GetVMAddrSlide() const {return slide_;}
148 
149  // Size of the image
150  mach_vm_size_t GetVMSize() const {return vmsize_;}
151 
152  // Task owning this loaded image
153  mach_port_t GetTask() {return task_;}
154 
155  // CPU type of the task
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.
162  bool Is64Bit() { return (GetCPUType() & CPU_ARCH_ABI64) == CPU_ARCH_ABI64; }
163 
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
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 //
207  public:
208  explicit DynamicImageRef(DynamicImage *inP) : p(inP) {}
209  // The copy constructor is required by STL
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.
240  public:
241  explicit DynamicImages(mach_port_t task);
242 
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.
250  int GetImageCount() const {return static_cast<int>(image_list_.size());}
251 
252  // Returns an individual image.
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.
265  mach_port_t GetTask() const {return task_;}
266 
267  // CPU type of the task
268  cpu_type_t GetCPUType() {return cpu_type_;}
269 
270  // Return true if the task is a 64-bit architecture.
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.
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 #else
289 #error "GetNativeCPUType not implemented for this architecture"
290 #endif
291  }
292 
293  private:
294  template<typename MachBits>
295  friend void ReadImageInfo(DynamicImages& images, uint64_t image_list_address);
296 
297  bool IsOurTask() {return task_ == mach_task_self();}
298 
299  // Initialization
300  void ReadImageInfoForTask();
301  uint64_t GetDyldAllImageInfosPointer();
302 
303  mach_port_t task_;
304  cpu_type_t cpu_type_; // CPU type of task_
305  vector<DynamicImageRef> image_list_;
306 };
307 
308 // Fill bytes with the contents of memory at a particular
309 // location in another task.
310 kern_return_t ReadTaskMemory(task_port_t target_task,
311  const uint64_t address,
312  size_t length,
313  vector<uint8_t> &bytes);
314 
315 } // namespace google_breakpad
316 
317 #endif // CLIENT_MAC_HANDLER_DYNAMIC_IMAGES_H__
mach_vm_address_t GetVMAddr() const
ptrdiff_t GetVMAddrSlide() const
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)
mach_port_t GetTask() const
#define CPU_ARCH_ABI64
static cpu_type_t GetNativeCPUType()
mach_header breakpad_mach_header
DynamicImage * GetImage(int i)
kern_return_t ReadTaskMemory(task_port_t target_task, const uint64_t address, size_t length, vector< uint8_t > &bytes)
#define CPU_TYPE_POWERPC64
struct google_breakpad::dyld_image_info32 dyld_image_info32
uint32_t GetFileTypeFromHeader(DynamicImage &image)
struct google_breakpad::dyld_image_info64 dyld_image_info64
struct google_breakpad::dyld_all_image_infos64 dyld_all_image_infos64
uint64_t GetLoadAddress() const
void ReadImageInfo(DynamicImages &images, uint64_t image_list_address)
DynamicImageRef(const DynamicImageRef &inRef)
DynamicImageRef(DynamicImage *inP)
mach_vm_size_t GetVMSize() const
struct google_breakpad::dyld_all_image_infos32 dyld_all_image_infos32
bool operator<(const DynamicImageRef &inRef) const
bool FindTextSection(DynamicImage &image)
segment_command breakpad_mach_segment_command
bool operator==(const DynamicImageRef &inInfo) const
bool operator<(const DynamicImage &inInfo)