minidump_generator.h revision 4621ee06914b2ebe963c93ea78fabf982cf670df
15ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// Copyright (c) 2006, Google Inc. 25ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// All rights reserved. 35ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// 45ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// Redistribution and use in source and binary forms, with or without 55ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// modification, are permitted provided that the following conditions are 65ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// met: 75ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// 85ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// * Redistributions of source code must retain the above copyright 95ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// notice, this list of conditions and the following disclaimer. 105ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// * Redistributions in binary form must reproduce the above 115ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// copyright notice, this list of conditions and the following disclaimer 125ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// in the documentation and/or other materials provided with the 135ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// distribution. 145ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// * Neither the name of Google Inc. nor the names of its 155ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// contributors may be used to endorse or promote products derived from 165ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// this software without specific prior written permission. 175ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// 185ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 195ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 205ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 215ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 225ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 235ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 245ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 255ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 265ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 275ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 285ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 295ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 305ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// minidump_generator.h: Create a minidump of the current MacOS process. 315ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 325ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis#ifndef CLIENT_MAC_GENERATOR_MINIDUMP_GENERATOR_H__ 335ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis#define CLIENT_MAC_GENERATOR_MINIDUMP_GENERATOR_H__ 345ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 355ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis#include <mach/mach.h> 365ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 375ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis#include <string> 385ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 395ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis#include "client/minidump_file_writer.h" 404621ee06914b2ebe963c93ea78fabf982cf670dfted.mielczarek#include "common/memory.h" 419be806efde6c55fbd7e9443d2700255835019a03ted.mielczarek#include "common/mac/macho_utilities.h" 424621ee06914b2ebe963c93ea78fabf982cf670dfted.mielczarek#include "google_breakpad/common/minidump_format.h" 435ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 44de2fd15db9a480c807ba337690669538a97756a4ladderbreaker#include "dynamic_images.h" 45de2fd15db9a480c807ba337690669538a97756a4ladderbreaker 46e5dc60822e5938fea2ae892ccddb906641ba174emmentovainamespace google_breakpad { 475ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 485ac2b9a569890f165478f91670dcdd553ce2d10ewaylonisusing std::string; 495ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 50867df1c65264c657ed71d68c3d266401686edcadnealsid#if TARGET_CPU_X86_64 || TARGET_CPU_PPC64 51867df1c65264c657ed71d68c3d266401686edcadnealsid#define TOP_OF_THREAD0_STACK 0x00007fff5fbff000 52867df1c65264c657ed71d68c3d266401686edcadnealsid#else 53867df1c65264c657ed71d68c3d266401686edcadnealsid#define TOP_OF_THREAD0_STACK 0xbffff000 54867df1c65264c657ed71d68c3d266401686edcadnealsid#endif 55867df1c65264c657ed71d68c3d266401686edcadnealsid 56867df1c65264c657ed71d68c3d266401686edcadnealsid#if TARGET_CPU_X86_64 57867df1c65264c657ed71d68c3d266401686edcadnealsidtypedef x86_thread_state64_t breakpad_thread_state_t; 58867df1c65264c657ed71d68c3d266401686edcadnealsidtypedef MDRawContextAMD64 MinidumpContext; 59867df1c65264c657ed71d68c3d266401686edcadnealsid#elif TARGET_CPU_X86 60867df1c65264c657ed71d68c3d266401686edcadnealsidtypedef i386_thread_state_t breakpad_thread_state_t; 61867df1c65264c657ed71d68c3d266401686edcadnealsidtypedef MDRawContextX86 MinidumpContext; 62867df1c65264c657ed71d68c3d266401686edcadnealsid#elif TARGET_CPU_PPC64 63867df1c65264c657ed71d68c3d266401686edcadnealsidtypedef ppc_thread_state64_t breakpad_thread_state_t; 64867df1c65264c657ed71d68c3d266401686edcadnealsidtypedef MDRawContextPPC64 MinidumpContext; 65867df1c65264c657ed71d68c3d266401686edcadnealsid#elif TARGET_CPU_PPC 66867df1c65264c657ed71d68c3d266401686edcadnealsidtypedef ppc_thread_state_t breakpad_thread_state_t; 67867df1c65264c657ed71d68c3d266401686edcadnealsidtypedef MDRawContextPPC MinidumpContext; 68867df1c65264c657ed71d68c3d266401686edcadnealsid#endif 69867df1c65264c657ed71d68c3d266401686edcadnealsid 70a0a0de39a8b25bea9ae18d98c4eb4c052c1a9864nealsid// Use the REGISTER_FROM_THREADSTATE to access a register name from the 71a0a0de39a8b25bea9ae18d98c4eb4c052c1a9864nealsid// breakpad_thread_state_t structure. 72b73230385c3d0d256a704ead20396714db43d7bbted.mielczarek#if __DARWIN_UNIX03 || TARGET_CPU_X86_64 || TARGET_CPU_PPC64 73a0a0de39a8b25bea9ae18d98c4eb4c052c1a9864nealsid// In The 10.5 SDK Headers Apple prepended __ to the variable names in the 74a0a0de39a8b25bea9ae18d98c4eb4c052c1a9864nealsid// i386_thread_state_t structure. There's no good way to tell what version of 75a0a0de39a8b25bea9ae18d98c4eb4c052c1a9864nealsid// the SDK we're compiling against so we just toggle on the same preprocessor 76a0a0de39a8b25bea9ae18d98c4eb4c052c1a9864nealsid// symbol Apple's headers use. 77a0a0de39a8b25bea9ae18d98c4eb4c052c1a9864nealsid#define REGISTER_FROM_THREADSTATE(a, b) ((a)->__ ## b) 78a0a0de39a8b25bea9ae18d98c4eb4c052c1a9864nealsid#else 79a0a0de39a8b25bea9ae18d98c4eb4c052c1a9864nealsid#define REGISTER_FROM_THREADSTATE(a, b) (a->b) 80a0a0de39a8b25bea9ae18d98c4eb4c052c1a9864nealsid#endif 81a0a0de39a8b25bea9ae18d98c4eb4c052c1a9864nealsid 825ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// Creates a minidump file of the current process. If there is exception data, 835ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// use SetExceptionInformation() to add this to the minidump. The minidump 845ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// file is generated by the Write() function. 855ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// Usage: 865ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// MinidumpGenerator minidump(); 875ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// minidump.Write("/tmp/minidump"); 885ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// 895ac2b9a569890f165478f91670dcdd553ce2d10ewaylonisclass MinidumpGenerator { 905ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis public: 915ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis MinidumpGenerator(); 92de2fd15db9a480c807ba337690669538a97756a4ladderbreaker MinidumpGenerator(mach_port_t crashing_task, mach_port_t handler_thread); 93de2fd15db9a480c807ba337690669538a97756a4ladderbreaker 945ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis ~MinidumpGenerator(); 955ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 965ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis // Return <dir>/<unique_name>.dmp 975ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis // Sets |unique_name| (if requested) to the unique name for the minidump 985ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis static string UniqueNameInDirectory(const string &dir, string *unique_name); 995ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 1005ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis // Write out the minidump into |path| 1015ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis // All of the components of |path| must exist and be writable 1025ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis // Return true if successful, false otherwise 1035ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis bool Write(const char *path); 1045ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 1055ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis // Specify some exception information, if applicable 10661e88c7ad7eb072977b4d4d26bcf8929b75af2d4ted.mielczarek void SetExceptionInformation(int type, int code, int subcode, 10761e88c7ad7eb072977b4d4d26bcf8929b75af2d4ted.mielczarek mach_port_t thread_name) { 1085ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis exception_type_ = type; 1095ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis exception_code_ = code; 11061e88c7ad7eb072977b4d4d26bcf8929b75af2d4ted.mielczarek exception_subcode_ = subcode; 1115ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis exception_thread_ = thread_name; 1125ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis } 1135ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 1145ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis // Gather system information. This should be call at least once before using 1155ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis // the MinidumpGenerator class. 1165ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis static void GatherSystemInformation(); 1175ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 1185ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis private: 1195ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis typedef bool (MinidumpGenerator::*WriteStreamFN)(MDRawDirectory *); 1205ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 1215ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis // Stream writers 1225ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis bool WriteThreadListStream(MDRawDirectory *thread_list_stream); 1234621ee06914b2ebe963c93ea78fabf982cf670dfted.mielczarek bool WriteMemoryListStream(MDRawDirectory *memory_list_stream); 1245ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis bool WriteExceptionStream(MDRawDirectory *exception_stream); 1255ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis bool WriteSystemInfoStream(MDRawDirectory *system_info_stream); 1265ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis bool WriteModuleListStream(MDRawDirectory *module_list_stream); 1275ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis bool WriteMiscInfoStream(MDRawDirectory *misc_info_stream); 128e5dc60822e5938fea2ae892ccddb906641ba174emmentovai bool WriteBreakpadInfoStream(MDRawDirectory *breakpad_info_stream); 1295ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 1305ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis // Helpers 131255bbe93ed7aef5418000339b6cdb5677bf9e4d6ted.mielczarek u_int64_t CurrentPCForStack(breakpad_thread_state_data_t state); 132867df1c65264c657ed71d68c3d266401686edcadnealsid bool WriteStackFromStartAddress(mach_vm_address_t start_addr, 1335ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis MDMemoryDescriptor *stack_location); 134255bbe93ed7aef5418000339b6cdb5677bf9e4d6ted.mielczarek bool WriteStack(breakpad_thread_state_data_t state, 1355ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis MDMemoryDescriptor *stack_location); 136255bbe93ed7aef5418000339b6cdb5677bf9e4d6ted.mielczarek bool WriteContext(breakpad_thread_state_data_t state, 1375ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis MDLocationDescriptor *register_location); 1385ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis bool WriteThreadStream(mach_port_t thread_id, MDRawThread *thread); 139d31c8b02925a1b20c09ee9ab771322353aea6267waylonis bool WriteCVRecord(MDRawModule *module, int cpu_type, 140d31c8b02925a1b20c09ee9ab771322353aea6267waylonis const char *module_path); 1415ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis bool WriteModuleStream(unsigned int index, MDRawModule *module); 142867df1c65264c657ed71d68c3d266401686edcadnealsid 143867df1c65264c657ed71d68c3d266401686edcadnealsid size_t CalculateStackSize(mach_vm_address_t start_addr); 144867df1c65264c657ed71d68c3d266401686edcadnealsid 145de2fd15db9a480c807ba337690669538a97756a4ladderbreaker int FindExecutableModule(); 1465ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 1475ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis // disallow copy ctor and operator= 1485ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis explicit MinidumpGenerator(const MinidumpGenerator &); 1495ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis void operator=(const MinidumpGenerator &); 1505ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 1515ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis // Use this writer to put the data to disk 1525ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis MinidumpFileWriter writer_; 1535ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 1545ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis // Exception information 1555ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis int exception_type_; 1565ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis int exception_code_; 15761e88c7ad7eb072977b4d4d26bcf8929b75af2d4ted.mielczarek int exception_subcode_; 1585ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis mach_port_t exception_thread_; 159de2fd15db9a480c807ba337690669538a97756a4ladderbreaker mach_port_t crashing_task_; 160de2fd15db9a480c807ba337690669538a97756a4ladderbreaker mach_port_t handler_thread_; 161de2fd15db9a480c807ba337690669538a97756a4ladderbreaker 1625ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis // System information 1635ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis static char build_string_[16]; 1645ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis static int os_major_version_; 1655ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis static int os_minor_version_; 1665ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis static int os_build_number_; 167de2fd15db9a480c807ba337690669538a97756a4ladderbreaker 168de2fd15db9a480c807ba337690669538a97756a4ladderbreaker // Information about dynamically loaded code 169de2fd15db9a480c807ba337690669538a97756a4ladderbreaker DynamicImages *dynamic_images_; 1704621ee06914b2ebe963c93ea78fabf982cf670dfted.mielczarek 1714621ee06914b2ebe963c93ea78fabf982cf670dfted.mielczarek // PageAllocator makes it possible to allocate memory 1724621ee06914b2ebe963c93ea78fabf982cf670dfted.mielczarek // directly from the system, even while handling an exception. 1734621ee06914b2ebe963c93ea78fabf982cf670dfted.mielczarek mutable PageAllocator allocator_; 1744621ee06914b2ebe963c93ea78fabf982cf670dfted.mielczarek 1754621ee06914b2ebe963c93ea78fabf982cf670dfted.mielczarek // Blocks of memory written to the dump. These are all currently 1764621ee06914b2ebe963c93ea78fabf982cf670dfted.mielczarek // written while writing the thread list stream, but saved here 1774621ee06914b2ebe963c93ea78fabf982cf670dfted.mielczarek // so a memory list stream can be written afterwards. 1784621ee06914b2ebe963c93ea78fabf982cf670dfted.mielczarek wasteful_vector<MDMemoryDescriptor> memory_blocks_; 1795ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis}; 1805ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 181e5dc60822e5938fea2ae892ccddb906641ba174emmentovai} // namespace google_breakpad 1825ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 1835ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis#endif // CLIENT_MAC_GENERATOR_MINIDUMP_GENERATOR_H__ 184