xref: /aosp_15_r20/external/google-breakpad/src/client/mac/handler/minidump_generator.h (revision 9712c20fc9bbfbac4935993a2ca0b3958c5adad2)
1 // Copyright 2006 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 // minidump_generator.h:  Create a minidump of the current MacOS process.
30 
31 #ifndef CLIENT_MAC_GENERATOR_MINIDUMP_GENERATOR_H__
32 #define CLIENT_MAC_GENERATOR_MINIDUMP_GENERATOR_H__
33 
34 #include <mach/mach.h>
35 #include <TargetConditionals.h>
36 
37 #include <string>
38 
39 #include "client/mac/handler/ucontext_compat.h"
40 #include "client/minidump_file_writer.h"
41 #include "common/memory_allocator.h"
42 #include "common/mac/macho_utilities.h"
43 #include "google_breakpad/common/minidump_format.h"
44 
45 #include "dynamic_images.h"
46 #include "mach_vm_compat.h"
47 
48 #if !TARGET_OS_IPHONE && (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7)
49   #define HAS_PPC_SUPPORT
50 #endif
51 #if defined(__arm__)
52 #define HAS_ARM_SUPPORT
53 #elif defined(__aarch64__)
54 #define HAS_ARM64_SUPPORT
55 #elif defined(__i386__) || defined(__x86_64__)
56   #define HAS_X86_SUPPORT
57 #endif
58 
59 namespace google_breakpad {
60 
61 using std::string;
62 
63 // Use the REGISTER_FROM_THREADSTATE to access a register name from the
64 // breakpad_thread_state_t structure.
65 #if __DARWIN_OPAQUE_ARM_THREAD_STATE64
66 #define ARRAY_REGISTER_FROM_THREADSTATE(a, b, i) ((a)->__##b[i])
67 #define GET_REGISTER_FROM_THREADSTATE_fp(a)                                    \
68   (reinterpret_cast<uintptr_t>((a)->__opaque_fp))
69 #define GET_REGISTER_FROM_THREADSTATE_lr(a)                                    \
70   (reinterpret_cast<uintptr_t>((a)->__opaque_lr))
71 #define GET_REGISTER_FROM_THREADSTATE_sp(a)                                    \
72   (reinterpret_cast<uintptr_t>((a)->__opaque_sp))
73 #define GET_REGISTER_FROM_THREADSTATE_pc(a)                                    \
74   (reinterpret_cast<uintptr_t>((a)->__opaque_pc))
75 #define GET_REGISTER_FROM_THREADSTATE_cpsr(a) ((a)->__cpsr)
76 #define GET_REGISTER_FROM_THREADSTATE_flags(a) ((a)->__opaque_flags)
77 #define REGISTER_FROM_THREADSTATE(a, b) (GET_REGISTER_FROM_THREADSTATE_##b(a))
78 #elif __DARWIN_UNIX03 || TARGET_CPU_X86_64 || TARGET_CPU_PPC64 || TARGET_CPU_ARM
79 // In The 10.5 SDK Headers Apple prepended __ to the variable names in the
80 // i386_thread_state_t structure.  There's no good way to tell what version of
81 // the SDK we're compiling against so we just toggle on the same preprocessor
82 // symbol Apple's headers use.
83 #define REGISTER_FROM_THREADSTATE(a, b) ((a)->__ ## b)
84 #define ARRAY_REGISTER_FROM_THREADSTATE(a, b, i)                               \
85   REGISTER_FROM_THREADSTATE(a, b[i])
86 #else
87 #define REGISTER_FROM_THREADSTATE(a, b) (a->b)
88 #define ARRAY_REGISTER_FROM_THREADSTATE(a, b, i)                               \
89   REGISTER_FROM_THREADSTATE(a, b[i])
90 #endif
91 
92 // Creates a minidump file of the current process.  If there is exception data,
93 // use SetExceptionInformation() to add this to the minidump.  The minidump
94 // file is generated by the Write() function.
95 // Usage:
96 // MinidumpGenerator minidump();
97 // minidump.Write("/tmp/minidump");
98 //
99 class MinidumpGenerator {
100  public:
101   MinidumpGenerator();
102   MinidumpGenerator(mach_port_t crashing_task, mach_port_t handler_thread);
103 
104   virtual ~MinidumpGenerator();
105 
106   // Return <dir>/<unique_name>.dmp
107   // Sets |unique_name| (if requested) to the unique name for the minidump
108   static string UniqueNameInDirectory(const string& dir, string* unique_name);
109 
110   // Write out the minidump into |path|
111   // All of the components of |path| must exist and be writable
112   // Return true if successful, false otherwise
113   bool Write(const char* path);
114 
115   // Specify some exception information, if applicable
SetExceptionInformation(int type,int code,int subcode,mach_port_t thread_name)116   void SetExceptionInformation(int type, int code, int subcode,
117                                mach_port_t thread_name) {
118     exception_type_ = type;
119     exception_code_ = code;
120     exception_subcode_ = subcode;
121     exception_thread_ = thread_name;
122   }
123 
124   // Specify the task context. If |task_context| is not NULL, it will be used
125   // to retrieve the context of the current thread, instead of using
126   // |thread_get_state|.
127   void SetTaskContext(breakpad_ucontext_t* task_context);
128 
129   // Gather system information.  This should be call at least once before using
130   // the MinidumpGenerator class.
131   static void GatherSystemInformation();
132 
133  protected:
134   // Overridable Stream writers
135   virtual bool WriteExceptionStream(MDRawDirectory* exception_stream);
136 
137   // Overridable Helper
138   virtual bool WriteThreadStream(mach_port_t thread_id, MDRawThread* thread);
139 
140  private:
141   typedef bool (MinidumpGenerator::*WriteStreamFN)(MDRawDirectory*);
142 
143   // Stream writers
144   bool WriteThreadListStream(MDRawDirectory* thread_list_stream);
145   bool WriteMemoryListStream(MDRawDirectory* memory_list_stream);
146   bool WriteSystemInfoStream(MDRawDirectory* system_info_stream);
147   bool WriteModuleListStream(MDRawDirectory* module_list_stream);
148   bool WriteMiscInfoStream(MDRawDirectory* misc_info_stream);
149   bool WriteBreakpadInfoStream(MDRawDirectory* breakpad_info_stream);
150 
151   // Helpers
152   uint64_t CurrentPCForStack(breakpad_thread_state_data_t state);
153   bool GetThreadState(thread_act_t target_thread, thread_state_t state,
154                       mach_msg_type_number_t* count);
155   bool WriteStackFromStartAddress(mach_vm_address_t start_addr,
156                                   MDMemoryDescriptor* stack_location);
157   bool WriteStack(breakpad_thread_state_data_t state,
158                   MDMemoryDescriptor* stack_location);
159   bool WriteContext(breakpad_thread_state_data_t state,
160                     MDLocationDescriptor* register_location);
161   bool WriteCVRecord(MDRawModule* module, int cpu_type,
162                      const char* module_path, bool in_memory);
163   bool WriteModuleStream(unsigned int index, MDRawModule* module);
164   size_t CalculateStackSize(mach_vm_address_t start_addr);
165   int  FindExecutableModule();
166 
167   // Per-CPU implementations of these methods
168 #ifdef HAS_ARM_SUPPORT
169   bool WriteStackARM(breakpad_thread_state_data_t state,
170                      MDMemoryDescriptor* stack_location);
171   bool WriteContextARM(breakpad_thread_state_data_t state,
172                        MDLocationDescriptor* register_location);
173   uint64_t CurrentPCForStackARM(breakpad_thread_state_data_t state);
174 #endif
175 #ifdef HAS_ARM64_SUPPORT
176   bool WriteStackARM64(breakpad_thread_state_data_t state,
177                        MDMemoryDescriptor* stack_location);
178   bool WriteContextARM64(breakpad_thread_state_data_t state,
179                          MDLocationDescriptor* register_location);
180   uint64_t CurrentPCForStackARM64(breakpad_thread_state_data_t state);
181 #endif
182 #ifdef HAS_PPC_SUPPORT
183   bool WriteStackPPC(breakpad_thread_state_data_t state,
184                      MDMemoryDescriptor* stack_location);
185   bool WriteContextPPC(breakpad_thread_state_data_t state,
186                        MDLocationDescriptor* register_location);
187   uint64_t CurrentPCForStackPPC(breakpad_thread_state_data_t state);
188   bool WriteStackPPC64(breakpad_thread_state_data_t state,
189                        MDMemoryDescriptor* stack_location);
190   bool WriteContextPPC64(breakpad_thread_state_data_t state,
191                        MDLocationDescriptor* register_location);
192   uint64_t CurrentPCForStackPPC64(breakpad_thread_state_data_t state);
193 #endif
194 #ifdef HAS_X86_SUPPORT
195   bool WriteStackX86(breakpad_thread_state_data_t state,
196                        MDMemoryDescriptor* stack_location);
197   bool WriteContextX86(breakpad_thread_state_data_t state,
198                        MDLocationDescriptor* register_location);
199   uint64_t CurrentPCForStackX86(breakpad_thread_state_data_t state);
200   bool WriteStackX86_64(breakpad_thread_state_data_t state,
201                         MDMemoryDescriptor* stack_location);
202   bool WriteContextX86_64(breakpad_thread_state_data_t state,
203                           MDLocationDescriptor* register_location);
204   uint64_t CurrentPCForStackX86_64(breakpad_thread_state_data_t state);
205 #endif
206 
207   // disallow copy ctor and operator=
208   explicit MinidumpGenerator(const MinidumpGenerator&);
209   void operator=(const MinidumpGenerator&);
210 
211  protected:
212   // Use this writer to put the data to disk
213   MinidumpFileWriter writer_;
214 
215  private:
216   // Exception information
217   int exception_type_;
218   int exception_code_;
219   int exception_subcode_;
220   mach_port_t exception_thread_;
221   mach_port_t crashing_task_;
222   mach_port_t handler_thread_;
223 
224   // CPU type of the task being dumped.
225   cpu_type_t cpu_type_;
226 
227   // System information
228   static char build_string_[16];
229   static int os_major_version_;
230   static int os_minor_version_;
231   static int os_build_number_;
232 
233   // Context of the task to dump.
234   breakpad_ucontext_t* task_context_;
235 
236   // Information about dynamically loaded code
237   DynamicImages* dynamic_images_;
238 
239   // PageAllocator makes it possible to allocate memory
240   // directly from the system, even while handling an exception.
241   mutable PageAllocator allocator_;
242 
243  protected:
244   // Blocks of memory written to the dump. These are all currently
245   // written while writing the thread list stream, but saved here
246   // so a memory list stream can be written afterwards.
247   wasteful_vector<MDMemoryDescriptor> memory_blocks_;
248 };
249 
250 }  // namespace google_breakpad
251 
252 #endif  // CLIENT_MAC_GENERATOR_MINIDUMP_GENERATOR_H__
253