xref: /aosp_15_r20/external/google-breakpad/src/client/mac/handler/dynamic_images.h (revision 9712c20fc9bbfbac4935993a2ca0b3958c5adad2)
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