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