parent
d5ebe9cc98
commit
83cee687bd
Binary file not shown.
Binary file not shown.
@ -0,0 +1,315 @@ |
||||
###################################################################### |
||||
# Automatically generated by qmake (2.01a) Fri Mar 13 16:41:05 2009 |
||||
###################################################################### |
||||
|
||||
TEMPLATE = lib |
||||
CONFIG += staticlib debug_and_release |
||||
|
||||
BUILD_DIR = build |
||||
CONFIG(debug, debug|release) { |
||||
BUILD_DIR = $$BUILD_DIR/debug |
||||
mac: TARGET = $$join(TARGET,,,_debug) |
||||
win32: TARGET = $$join(TARGET,,d) |
||||
} |
||||
CONFIG(release, debug|release) { |
||||
BUILD_DIR = $$BUILD_DIR/release |
||||
CONFIG += warn_off |
||||
} |
||||
|
||||
BREAKPAD_DIR = "$$[UNIBOARD_DIR]/thirdparty/google-breakpad/r318" |
||||
headersHandlerMac.path = "$$BREAKPAD_DIR/include/google_breakpad/client/mac/handler" |
||||
headersHandlerMac.files = "src/client/mac/handler/*.h" |
||||
|
||||
headersHandlerWin.path = "$$BREAKPAD_DIR/include/google_breakpad/client/windows/handler" |
||||
headersHandlerWin.files = "src/client/windows/handler/*.h" |
||||
|
||||
headersClient.path = "$$BREAKPAD_DIR/include/google_breakpad/client" |
||||
headersClient.files = "src/client/*.h" |
||||
|
||||
headersClientCommonWin.path = "$$BREAKPAD_DIR/include/google_breakpad/client/windows/common" |
||||
headersClientCommonWin.files = "src/client/windows/common/*.h" |
||||
|
||||
headersClientCrashGenerationWin.path = "$$BREAKPAD_DIR/include/google_breakpad/client/windows/crash_generation" |
||||
headersClientCrashGenerationWin.files = "src/client/windows/crash_generation/*.h" |
||||
|
||||
headersClientSenderWin.path = "$$BREAKPAD_DIR/include/google_breakpad/client/windows/sender" |
||||
headersClientSenderWin.files = "src/client/windows/sender/*.h" |
||||
|
||||
headersCommon.path = "$$BREAKPAD_DIR/include/google_breakpad/common" |
||||
headersCommon.files = "src/common/*.h" |
||||
|
||||
headersCommonWin.path = "$$BREAKPAD_DIR/include/google_breakpad/common/windows" |
||||
headersCommonWin.files = "src/common/windows/*.h" |
||||
|
||||
headersGbCommon.path = "$$BREAKPAD_DIR/include/google_breakpad/google_breakpad/common" |
||||
headersGbCommon.files = "src/google_breakpad/common/*.h" |
||||
|
||||
headersGbProcessor.path = "$$BREAKPAD_DIR/include/google_breakpad/google_breakpad/processor" |
||||
headersGbProcessor.files = "src/google_breakpad/processor/*.h" |
||||
|
||||
headersProcessor.path = "$$BREAKPAD_DIR/include/google_breakpad/processor" |
||||
headersProcessor.files = "src/processor/*.h" |
||||
|
||||
INSTALLS += "headersHandlerMac" "headersHandlerWin" "headersClient" "headersClientCommonWin" "headersCommonWin"\ |
||||
"headersClientCrashGenerationWin" "headersClientSenderWin" "headersCommon" "headersGbCommon" "headersGbProcessor" "headersProcessor" |
||||
|
||||
INCLUDEPATH += src \ |
||||
src/client \ |
||||
src/google_breakpad/common \ |
||||
src/common \ |
||||
src/processor \ |
||||
src/google_breakpad/processor |
||||
|
||||
# Input |
||||
HEADERS += src/client/minidump_file_writer-inl.h \ |
||||
src/client/minidump_file_writer.h \ |
||||
src/common/convert_UTF.h \ |
||||
src/common/md5.h \ |
||||
src/common/string_conversion.h \ |
||||
src/processor/address_map-inl.h \ |
||||
src/processor/address_map.h \ |
||||
src/processor/basic_code_module.h \ |
||||
src/processor/basic_code_modules.h \ |
||||
src/processor/contained_range_map-inl.h \ |
||||
src/processor/contained_range_map.h \ |
||||
src/processor/linked_ptr.h \ |
||||
src/processor/logging.h \ |
||||
src/processor/pathname_stripper.h \ |
||||
src/processor/postfix_evaluator-inl.h \ |
||||
src/processor/postfix_evaluator.h \ |
||||
src/processor/range_map-inl.h \ |
||||
src/processor/range_map.h \ |
||||
src/processor/scoped_ptr.h \ |
||||
src/processor/simple_symbol_supplier.h \ |
||||
src/processor/stack_frame_info.h \ |
||||
src/processor/stackwalker_amd64.h \ |
||||
src/processor/stackwalker_ppc.h \ |
||||
src/processor/stackwalker_sparc.h \ |
||||
src/processor/stackwalker_x86.h \ |
||||
src/google_breakpad/common/breakpad_types.h \ |
||||
src/google_breakpad/common/minidump_cpu_amd64.h \ |
||||
src/google_breakpad/common/minidump_cpu_ppc.h \ |
||||
src/google_breakpad/common/minidump_cpu_ppc64.h \ |
||||
src/google_breakpad/common/minidump_cpu_sparc.h \ |
||||
src/google_breakpad/common/minidump_cpu_x86.h \ |
||||
src/google_breakpad/common/minidump_exception_linux.h \ |
||||
src/google_breakpad/common/minidump_exception_mac.h \ |
||||
src/google_breakpad/common/minidump_exception_solaris.h \ |
||||
src/google_breakpad/common/minidump_exception_win32.h \ |
||||
src/google_breakpad/common/minidump_format.h \ |
||||
src/google_breakpad/common/minidump_size.h \ |
||||
src/google_breakpad/processor/basic_source_line_resolver.h \ |
||||
src/google_breakpad/processor/call_stack.h \ |
||||
src/google_breakpad/processor/code_module.h \ |
||||
src/google_breakpad/processor/code_modules.h \ |
||||
src/google_breakpad/processor/memory_region.h \ |
||||
src/google_breakpad/processor/minidump.h \ |
||||
src/google_breakpad/processor/minidump_processor.h \ |
||||
src/google_breakpad/processor/process_state.h \ |
||||
src/google_breakpad/processor/source_line_resolver_interface.h \ |
||||
src/google_breakpad/processor/stack_frame.h \ |
||||
src/google_breakpad/processor/stack_frame_cpu.h \ |
||||
src/google_breakpad/processor/stackwalker.h \ |
||||
src/google_breakpad/processor/symbol_supplier.h \ |
||||
src/google_breakpad/processor/system_info.h |
||||
|
||||
|
||||
win32 { |
||||
|
||||
DESTDIR = "lib/win32" |
||||
OBJECTS_DIR = $$BUILD_DIR/objects |
||||
MOC_DIR = $$BUILD_DIR/moc |
||||
RCC_DIR = $$BUILD_DIR/rcc |
||||
UI_DIR = $$BUILD_DIR/ui |
||||
|
||||
INCLUDEPATH += "C:\Program Files\Microsoft Visual Studio 9.0\DIA SDK\include" |
||||
|
||||
HEADERS += src/common/windows/guid_string.h \ |
||||
src/common/windows/http_upload.h \ |
||||
src/common/windows/pdb_source_line_writer.h \ |
||||
src/common/windows/string_utils-inl.h \ |
||||
src/client/windows/common/auto_critical_section.h \ |
||||
src/client/windows/common/ipc_protocol.h \ |
||||
src/client/windows/crash_generation/client_info.h \ |
||||
src/client/windows/crash_generation/crash_generation_client.h \ |
||||
src/client/windows/crash_generation/crash_generation_server.h \ |
||||
src/client/windows/crash_generation/minidump_generator.h \ |
||||
src/client/windows/handler/exception_handler.h \ |
||||
src/client/windows/sender/crash_report_sender.h \ |
||||
src/tools/windows/converter/ms_symbol_server_converter.h \ |
||||
src/client/windows/tests/crash_generation_app/abstract_class.h \ |
||||
src/client/windows/tests/crash_generation_app/crash_generation_app.h \ |
||||
src/client/windows/tests/crash_generation_app/precompile.h \ |
||||
src/client/windows/tests/crash_generation_app/resource.h |
||||
|
||||
SOURCES += src/common/windows/guid_string.cc \ |
||||
src/common/windows/http_upload.cc \ |
||||
src/common/windows/pdb_source_line_writer.cc \ |
||||
src/common/windows/string_utils.cc \ |
||||
src/client/windows/crash_generation/client_info.cc \ |
||||
src/client/windows/crash_generation/crash_generation_client.cc \ |
||||
src/client/windows/crash_generation/crash_generation_server.cc \ |
||||
src/client/windows/crash_generation/minidump_generator.cc \ |
||||
src/client/windows/handler/exception_handler.cc \ |
||||
src/client/windows/sender/crash_report_sender.cc \ |
||||
src/tools/windows/dump_syms/dump_syms.cc \ |
||||
src/tools/windows/symupload/symupload.cc |
||||
} |
||||
|
||||
macx { |
||||
|
||||
DESTDIR = "lib/macx" |
||||
OBJECTS_DIR = $$BUILD_DIR |
||||
|
||||
CONFIG += x86 ppc |
||||
QMAKE_MACOSX_DEPLOYMENT_TARGET = "10.4" |
||||
|
||||
INCLUDEPATH += src/common/mac \ |
||||
src/client/mac/handler \ |
||||
src/common/mac/dwarf |
||||
|
||||
HEADERS += src/common/mac/dump_syms.h \ |
||||
src/common/mac/file_id.h \ |
||||
src/common/mac/HTTPMultipartUpload.h \ |
||||
src/common/mac/macho_id.h \ |
||||
src/common/mac/macho_utilities.h \ |
||||
src/common/mac/macho_walker.h \ |
||||
src/common/mac/string_utilities.h \ |
||||
src/client/mac/handler/breakpad_exc_server.h \ |
||||
src/client/mac/handler/breakpad_nlist_64.h \ |
||||
src/client/mac/handler/dynamic_images.h \ |
||||
src/client/mac/handler/exception_handler.h \ |
||||
src/client/mac/handler/minidump_generator.h \ |
||||
src/client/mac/handler/protected_memory_allocator.h \ |
||||
src/common/mac/dwarf/bytereader-inl.h \ |
||||
src/common/mac/dwarf/bytereader.h \ |
||||
src/common/mac/dwarf/dwarf2enums.h \ |
||||
src/common/mac/dwarf/dwarf2reader.h \ |
||||
src/common/mac/dwarf/functioninfo.h \ |
||||
src/common/mac/dwarf/line_state_machine.h \ |
||||
src/common/mac/dwarf/types.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/GTMDefines.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/AppKit/GTMCarbonEvent.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/AppKit/GTMDelegatingTableColumn.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/AppKit/GTMHotKeyTextField.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/AppKit/GTMLargeTypeWindow.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/AppKit/GTMLinearRGBShading.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/AppKit/GTMLoginItems.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/AppKit/GTMNSBezierPath+CGPath.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/AppKit/GTMNSBezierPath+RoundRect.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/AppKit/GTMNSBezierPath+Shading.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/AppKit/GTMNSColor+Luminance.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/AppKit/GTMNSImage+Scaling.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/AppKit/GTMNSWorkspace+Running.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/AppKit/GTMShading.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/AppKit/GTMTheme.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/DebugUtils/GTMDebugSelectorValidation.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/DebugUtils/GTMDebugThreadValidation.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/DebugUtils/GTMMethodCheck.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/Foundation/GTMAbstractDOListener.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/Foundation/GTMBase64.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/Foundation/GTMCalculatedRange.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/Foundation/GTMExceptionalInlines.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/Foundation/GTMFileSystemKQueue.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/Foundation/GTMFourCharCode.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/Foundation/GTMGarbageCollection.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/Foundation/GTMGeometryUtils.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/Foundation/GTMHTTPFetcher.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/Foundation/GTMHTTPServer.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/Foundation/GTMLightweightProxy.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/Foundation/GTMLogger+ASL.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/Foundation/GTMLogger.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/Foundation/GTMLoggerRingBufferWriter.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/Foundation/GTMNSAppleEventDescriptor+Foundation.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/Foundation/GTMNSAppleEventDescriptor+Handler.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/Foundation/GTMNSAppleScript+Handler.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/Foundation/GTMNSArray+Merge.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/Foundation/GTMNSData+zlib.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/Foundation/GTMNSDictionary+URLArguments.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/Foundation/GTMNSEnumerator+Filter.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/Foundation/GTMNSFileManager+Carbon.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/Foundation/GTMNSFileManager+Path.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/Foundation/GTMNSObject+KeyValueObserving.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/Foundation/GTMNSString+FindFolder.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/Foundation/GTMNSString+HTML.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/Foundation/GTMNSString+Replace.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/Foundation/GTMNSString+URLArguments.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/Foundation/GTMNSString+XML.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/Foundation/GTMObjC2Runtime.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/Foundation/GTMObjectSingleton.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/Foundation/GTMPath.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/Foundation/GTMProgressMonitorInputStream.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/Foundation/GTMRegex.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/Foundation/GTMScriptRunner.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/Foundation/GTMSignalHandler.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/Foundation/GTMSQLite.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/Foundation/GTMStackTrace.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/Foundation/GTMSystemVersion.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/Foundation/GTMTransientRootPortProxy.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/Foundation/GTMTransientRootProxy.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/Foundation/GTMValidatingContainers.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/iPhone/GTMABAddressBook.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/iPhone/GTMUIFont+LineHeight.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/UnitTesting/GTMAppKit+UnitTesting.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/UnitTesting/GTMCALayer+UnitTesting.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/UnitTesting/GTMIPhoneUnitTestDelegate.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/UnitTesting/GTMNSObject+BindingUnitTesting.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/UnitTesting/GTMNSObject+UnitTesting.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/UnitTesting/GTMSenTestCase.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/UnitTesting/GTMTestHTTPServer.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/UnitTesting/GTMTestTimer.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/UnitTesting/GTMUIKit+UnitTesting.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/UnitTesting/GTMUnitTestDevLog.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/UnitTesting/GTMUnitTestingTest.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/UnitTesting/GTMUnitTestingUtilities.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/SpotlightPlugins/AppleScript/PluginID.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/SpotlightPlugins/InterfaceBuilder/PluginID.h \ |
||||
src/common/mac/externals/google-toolbox-for-mac/SpotlightPlugins/XcodeProject/PluginID.h |
||||
|
||||
SOURCES += src/common/convert_UTF.c \ |
||||
src/common/md5.c \ |
||||
src/common/string_conversion.cc \ |
||||
src/client/minidump_file_writer.cc \ |
||||
src/client/minidump_file_writer_unittest.cc \ |
||||
src/processor/address_map_unittest.cc \ |
||||
src/processor/basic_code_modules.cc \ |
||||
src/processor/basic_source_line_resolver.cc \ |
||||
src/processor/basic_source_line_resolver_unittest.cc \ |
||||
src/processor/call_stack.cc \ |
||||
src/processor/contained_range_map_unittest.cc \ |
||||
src/processor/logging.cc \ |
||||
src/processor/minidump.cc \ |
||||
src/processor/minidump_dump.cc \ |
||||
src/processor/minidump_processor.cc \ |
||||
src/processor/minidump_processor_unittest.cc \ |
||||
src/processor/minidump_stackwalk.cc \ |
||||
src/processor/pathname_stripper.cc \ |
||||
src/processor/pathname_stripper_unittest.cc \ |
||||
src/processor/postfix_evaluator_unittest.cc \ |
||||
src/processor/process_state.cc \ |
||||
src/processor/range_map_unittest.cc \ |
||||
src/processor/simple_symbol_supplier.cc \ |
||||
src/processor/stackwalker.cc \ |
||||
src/processor/stackwalker_amd64.cc \ |
||||
src/processor/stackwalker_ppc.cc \ |
||||
src/processor/stackwalker_selftest.cc \ |
||||
src/processor/stackwalker_sparc.cc \ |
||||
src/processor/stackwalker_x86.cc \ |
||||
src/common/mac/file_id.cc \ |
||||
src/common/mac/macho_id.cc \ |
||||
src/common/mac/macho_utilities.cc \ |
||||
src/common/mac/macho_walker.cc \ |
||||
src/common/mac/string_utilities.cc \ |
||||
src/client/mac/handler/breakpad_exc_server.c \ |
||||
src/client/mac/handler/breakpad_nlist_64.cc \ |
||||
src/client/mac/handler/dynamic_images.cc \ |
||||
src/client/mac/handler/exception_handler.cc \ |
||||
src/client/mac/handler/exception_handler_test.cc \ |
||||
src/client/mac/handler/minidump_generator.cc \ |
||||
src/client/mac/handler/minidump_generator_test.cc \ |
||||
src/client/mac/handler/protected_memory_allocator.cc \ |
||||
src/common/mac/dwarf/bytereader.cc \ |
||||
src/common/mac/dwarf/dwarf2reader.cc \ |
||||
src/common/mac/dwarf/functioninfo.cc |
||||
} |
||||
|
@ -0,0 +1,258 @@ |
||||
#ifndef _exc_user_ |
||||
#define _exc_user_ |
||||
|
||||
/* Module exc */ |
||||
|
||||
#include <string.h> |
||||
#include <mach/ndr.h> |
||||
#include <mach/boolean.h> |
||||
#include <mach/kern_return.h> |
||||
#include <mach/notify.h> |
||||
#include <mach/mach_types.h> |
||||
#include <mach/message.h> |
||||
#include <mach/mig_errors.h> |
||||
#include <mach/port.h> |
||||
|
||||
#ifdef AUTOTEST |
||||
#ifndef FUNCTION_PTR_T |
||||
#define FUNCTION_PTR_T |
||||
typedef void (*function_ptr_t)(mach_port_t, char *, mach_msg_type_number_t); |
||||
typedef struct { |
||||
char *name; |
||||
function_ptr_t function; |
||||
} function_table_entry; |
||||
typedef function_table_entry *function_table_t; |
||||
#endif /* FUNCTION_PTR_T */ |
||||
#endif /* AUTOTEST */ |
||||
|
||||
#ifndef exc_MSG_COUNT |
||||
#define exc_MSG_COUNT 3 |
||||
#endif /* exc_MSG_COUNT */ |
||||
|
||||
#include <mach/std_types.h> |
||||
#include <mach/mig.h> |
||||
#include <mach/mig.h> |
||||
#include <mach/mach_types.h> |
||||
|
||||
#ifdef __BeforeMigUserHeader |
||||
__BeforeMigUserHeader |
||||
#endif /* __BeforeMigUserHeader */ |
||||
|
||||
#include <sys/cdefs.h> |
||||
__BEGIN_DECLS |
||||
|
||||
|
||||
/* Routine exception_raise */ |
||||
#ifdef mig_external |
||||
mig_external |
||||
#else |
||||
extern |
||||
#endif /* mig_external */ |
||||
kern_return_t exception_raise |
||||
( |
||||
mach_port_t exception_port, |
||||
mach_port_t thread, |
||||
mach_port_t task, |
||||
exception_type_t exception, |
||||
exception_data_t code, |
||||
mach_msg_type_number_t codeCnt |
||||
); |
||||
|
||||
/* Routine exception_raise_state */ |
||||
#ifdef mig_external |
||||
mig_external |
||||
#else |
||||
extern |
||||
#endif /* mig_external */ |
||||
kern_return_t exception_raise_state |
||||
( |
||||
mach_port_t exception_port, |
||||
exception_type_t exception, |
||||
const exception_data_t code, |
||||
mach_msg_type_number_t codeCnt, |
||||
int *flavor, |
||||
const thread_state_t old_state, |
||||
mach_msg_type_number_t old_stateCnt, |
||||
thread_state_t new_state, |
||||
mach_msg_type_number_t *new_stateCnt |
||||
); |
||||
|
||||
/* Routine exception_raise_state_identity */ |
||||
#ifdef mig_external |
||||
mig_external |
||||
#else |
||||
extern |
||||
#endif /* mig_external */ |
||||
kern_return_t exception_raise_state_identity |
||||
( |
||||
mach_port_t exception_port, |
||||
mach_port_t thread, |
||||
mach_port_t task, |
||||
exception_type_t exception, |
||||
exception_data_t code, |
||||
mach_msg_type_number_t codeCnt, |
||||
int *flavor, |
||||
thread_state_t old_state, |
||||
mach_msg_type_number_t old_stateCnt, |
||||
thread_state_t new_state, |
||||
mach_msg_type_number_t *new_stateCnt |
||||
); |
||||
|
||||
__END_DECLS |
||||
|
||||
/********************** Caution **************************/ |
||||
/* The following data types should be used to calculate */ |
||||
/* maximum message sizes only. The actual message may be */ |
||||
/* smaller, and the position of the arguments within the */ |
||||
/* message layout may vary from what is presented here. */ |
||||
/* For example, if any of the arguments are variable- */ |
||||
/* sized, and less than the maximum is sent, the data */ |
||||
/* will be packed tight in the actual message to reduce */ |
||||
/* the presence of holes. */ |
||||
/********************** Caution **************************/ |
||||
|
||||
/* typedefs for all requests */ |
||||
|
||||
#ifndef __Request__exc_subsystem__defined |
||||
#define __Request__exc_subsystem__defined |
||||
|
||||
#ifdef __MigPackStructs |
||||
#pragma pack(4) |
||||
#endif |
||||
typedef struct { |
||||
mach_msg_header_t Head; |
||||
/* start of the kernel processed data */ |
||||
mach_msg_body_t msgh_body; |
||||
mach_msg_port_descriptor_t thread; |
||||
mach_msg_port_descriptor_t task; |
||||
/* end of the kernel processed data */ |
||||
NDR_record_t NDR; |
||||
exception_type_t exception; |
||||
mach_msg_type_number_t codeCnt; |
||||
integer_t code[2]; |
||||
} __Request__exception_raise_t; |
||||
#ifdef __MigPackStructs |
||||
#pragma pack() |
||||
#endif |
||||
|
||||
#ifdef __MigPackStructs |
||||
#pragma pack(4) |
||||
#endif |
||||
typedef struct { |
||||
mach_msg_header_t Head; |
||||
NDR_record_t NDR; |
||||
exception_type_t exception; |
||||
mach_msg_type_number_t codeCnt; |
||||
integer_t code[2]; |
||||
int flavor; |
||||
mach_msg_type_number_t old_stateCnt; |
||||
natural_t old_state[144]; |
||||
} __Request__exception_raise_state_t; |
||||
#ifdef __MigPackStructs |
||||
#pragma pack() |
||||
#endif |
||||
|
||||
#ifdef __MigPackStructs |
||||
#pragma pack(4) |
||||
#endif |
||||
typedef struct { |
||||
mach_msg_header_t Head; |
||||
/* start of the kernel processed data */ |
||||
mach_msg_body_t msgh_body; |
||||
mach_msg_port_descriptor_t thread; |
||||
mach_msg_port_descriptor_t task; |
||||
/* end of the kernel processed data */ |
||||
NDR_record_t NDR; |
||||
exception_type_t exception; |
||||
mach_msg_type_number_t codeCnt; |
||||
integer_t code[2]; |
||||
int flavor; |
||||
mach_msg_type_number_t old_stateCnt; |
||||
natural_t old_state[144]; |
||||
} __Request__exception_raise_state_identity_t; |
||||
#ifdef __MigPackStructs |
||||
#pragma pack() |
||||
#endif |
||||
#endif /* !__Request__exc_subsystem__defined */ |
||||
|
||||
/* union of all requests */ |
||||
|
||||
#ifndef __RequestUnion__exc_subsystem__defined |
||||
#define __RequestUnion__exc_subsystem__defined |
||||
union __RequestUnion__exc_subsystem { |
||||
__Request__exception_raise_t Request_exception_raise; |
||||
__Request__exception_raise_state_t Request_exception_raise_state; |
||||
__Request__exception_raise_state_identity_t Request_exception_raise_state_identity; |
||||
}; |
||||
#endif /* !__RequestUnion__exc_subsystem__defined */ |
||||
/* typedefs for all replies */ |
||||
|
||||
#ifndef __Reply__exc_subsystem__defined |
||||
#define __Reply__exc_subsystem__defined |
||||
|
||||
#ifdef __MigPackStructs |
||||
#pragma pack(4) |
||||
#endif |
||||
typedef struct { |
||||
mach_msg_header_t Head; |
||||
NDR_record_t NDR; |
||||
kern_return_t RetCode; |
||||
} __Reply__exception_raise_t; |
||||
#ifdef __MigPackStructs |
||||
#pragma pack() |
||||
#endif |
||||
|
||||
#ifdef __MigPackStructs |
||||
#pragma pack(4) |
||||
#endif |
||||
typedef struct { |
||||
mach_msg_header_t Head; |
||||
NDR_record_t NDR; |
||||
kern_return_t RetCode; |
||||
int flavor; |
||||
mach_msg_type_number_t new_stateCnt; |
||||
natural_t new_state[144]; |
||||
} __Reply__exception_raise_state_t; |
||||
#ifdef __MigPackStructs |
||||
#pragma pack() |
||||
#endif |
||||
|
||||
#ifdef __MigPackStructs |
||||
#pragma pack(4) |
||||
#endif |
||||
typedef struct { |
||||
mach_msg_header_t Head; |
||||
NDR_record_t NDR; |
||||
kern_return_t RetCode; |
||||
int flavor; |
||||
mach_msg_type_number_t new_stateCnt; |
||||
natural_t new_state[144]; |
||||
} __Reply__exception_raise_state_identity_t; |
||||
#ifdef __MigPackStructs |
||||
#pragma pack() |
||||
#endif |
||||
#endif /* !__Reply__exc_subsystem__defined */ |
||||
|
||||
/* union of all replies */ |
||||
|
||||
#ifndef __ReplyUnion__exc_subsystem__defined |
||||
#define __ReplyUnion__exc_subsystem__defined |
||||
union __ReplyUnion__exc_subsystem { |
||||
__Reply__exception_raise_t Reply_exception_raise; |
||||
__Reply__exception_raise_state_t Reply_exception_raise_state; |
||||
__Reply__exception_raise_state_identity_t Reply_exception_raise_state_identity; |
||||
}; |
||||
#endif /* !__RequestUnion__exc_subsystem__defined */ |
||||
|
||||
#ifndef subsystem_to_name_map_exc |
||||
#define subsystem_to_name_map_exc \ |
||||
{ "exception_raise", 2401 },\
|
||||
{ "exception_raise_state", 2402 },\
|
||||
{ "exception_raise_state_identity", 2403 } |
||||
#endif |
||||
|
||||
#ifdef __AfterMigUserHeader |
||||
__AfterMigUserHeader |
||||
#endif /* __AfterMigUserHeader */ |
||||
|
||||
#endif /* _exc_user_ */ |
@ -0,0 +1,43 @@ |
||||
// Copyright (c) 2008, Google Inc.
|
||||
// All rights reserved
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// breakpad_nlist.h
|
||||
//
|
||||
// This file is meant to provide a header for clients of the modified
|
||||
// nlist function implemented to work on 64-bit.
|
||||
|
||||
#ifndef CLIENT_MAC_HANDLER_BREAKPAD_NLIST_H__ |
||||
|
||||
typedef struct nlist_64 breakpad_nlist; |
||||
|
||||
int |
||||
breakpad_nlist_64(const char *name, |
||||
breakpad_nlist *list, |
||||
const char **symbolNames); |
||||
|
||||
#endif /* CLIENT_MAC_HANDLER_BREAKPAD_NLIST_H__ */ |
@ -0,0 +1,297 @@ |
||||
// Copyright (c) 2007, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// dynamic_images.h
|
||||
//
|
||||
// Implements most of the function of the dyld API, but allowing an
|
||||
// arbitrary task to be introspected, unlike the dyld API which
|
||||
// only allows operation on the current task. The current implementation
|
||||
// is limited to use by 32-bit tasks.
|
||||
|
||||
#ifndef CLIENT_MAC_HANDLER_DYNAMIC_IMAGES_H__ |
||||
#define CLIENT_MAC_HANDLER_DYNAMIC_IMAGES_H__ |
||||
|
||||
#include <mach/mach.h> |
||||
#include <mach-o/dyld.h> |
||||
#include <mach-o/loader.h> |
||||
#include <sys/types.h> |
||||
#include <vector> |
||||
|
||||
namespace google_breakpad { |
||||
|
||||
using std::vector; |
||||
|
||||
//==============================================================================
|
||||
// The memory layout of this struct matches the dyld_image_info struct
|
||||
// defined in "dyld_gdb.h" in the darwin source.
|
||||
typedef struct dyld_image_info { |
||||
struct mach_header *load_address_; |
||||
char *file_path_; |
||||
uintptr_t file_mod_date_; |
||||
} dyld_image_info; |
||||
|
||||
//==============================================================================
|
||||
// This is as defined in "dyld_gdb.h" in the darwin source.
|
||||
// _dyld_all_image_infos (in dyld) is a structure of this type
|
||||
// which will be used to determine which dynamic code has been loaded.
|
||||
typedef struct dyld_all_image_infos { |
||||
uint32_t version; // == 1 in Mac OS X 10.4
|
||||
uint32_t infoArrayCount; |
||||
const struct dyld_image_info *infoArray; |
||||
void* notification; |
||||
bool processDetachedFromSharedRegion; |
||||
} dyld_all_image_infos; |
||||
|
||||
// some typedefs to isolate 64/32 bit differences
|
||||
#ifdef __LP64__ |
||||
typedef mach_header_64 breakpad_mach_header; |
||||
typedef segment_command_64 breakpad_mach_segment_command; |
||||
#else |
||||
typedef mach_header breakpad_mach_header; |
||||
typedef segment_command breakpad_mach_segment_command; |
||||
#endif |
||||
|
||||
//==============================================================================
|
||||
// A simple wrapper for a mach_header
|
||||
//
|
||||
// This could be fleshed out with some more interesting methods.
|
||||
class MachHeader { |
||||
public: |
||||
explicit MachHeader(const breakpad_mach_header &header) : header_(header) {} |
||||
|
||||
void Print() { |
||||
printf("magic\t\t: %4x\n", header_.magic); |
||||
printf("cputype\t\t: %d\n", header_.cputype); |
||||
printf("cpusubtype\t: %d\n", header_.cpusubtype); |
||||
printf("filetype\t: %d\n", header_.filetype); |
||||
printf("ncmds\t\t: %d\n", header_.ncmds); |
||||
printf("sizeofcmds\t: %d\n", header_.sizeofcmds); |
||||
printf("flags\t\t: %d\n", header_.flags); |
||||
} |
||||
|
||||
breakpad_mach_header header_; |
||||
}; |
||||
|
||||
//==============================================================================
|
||||
// Represents a single dynamically loaded mach-o image
|
||||
class DynamicImage { |
||||
public: |
||||
DynamicImage(breakpad_mach_header *header, // we take ownership
|
||||
int header_size, // includes load commands
|
||||
breakpad_mach_header *load_address, |
||||
char *inFilePath, |
||||
uintptr_t image_mod_date, |
||||
mach_port_t task) |
||||
: header_(header), |
||||
header_size_(header_size), |
||||
load_address_(load_address), |
||||
file_mod_date_(image_mod_date), |
||||
task_(task) { |
||||
InitializeFilePath(inFilePath); |
||||
CalculateMemoryAndVersionInfo(); |
||||
} |
||||
|
||||
~DynamicImage() { |
||||
if (file_path_) { |
||||
free(file_path_); |
||||
} |
||||
free(header_); |
||||
} |
||||
|
||||
// Returns pointer to a local copy of the mach_header plus load commands
|
||||
breakpad_mach_header *GetMachHeader() {return header_;} |
||||
|
||||
// Size of mach_header plus load commands
|
||||
int GetHeaderSize() const {return header_size_;} |
||||
|
||||
// Full path to mach-o binary
|
||||
char *GetFilePath() {return file_path_;} |
||||
|
||||
uintptr_t GetModDate() const {return file_mod_date_;} |
||||
|
||||
// Actual address where the image was loaded
|
||||
breakpad_mach_header *GetLoadAddress() const {return load_address_;} |
||||
|
||||
// Address where the image should be loaded
|
||||
mach_vm_address_t GetVMAddr() const {return vmaddr_;} |
||||
|
||||
// Difference between GetLoadAddress() and GetVMAddr()
|
||||
ptrdiff_t GetVMAddrSlide() const {return slide_;} |
||||
|
||||
// Size of the image
|
||||
mach_vm_size_t GetVMSize() const {return vmsize_;} |
||||
|
||||
// Task owning this loaded image
|
||||
mach_port_t GetTask() {return task_;} |
||||
|
||||
uint32_t GetVersion() {return version_;} |
||||
// For sorting
|
||||
bool operator<(const DynamicImage &inInfo) { |
||||
return GetLoadAddress() < inInfo.GetLoadAddress(); |
||||
} |
||||
|
||||
// Debugging
|
||||
void Print(); |
||||
|
||||
private: |
||||
friend class DynamicImages; |
||||
|
||||
// Sanity checking
|
||||
bool IsValid() {return GetVMSize() != 0;} |
||||
|
||||
// Makes local copy of file path to mach-o binary
|
||||
void InitializeFilePath(char *inFilePath) { |
||||
if (inFilePath) { |
||||
size_t path_size = 1 + strlen(inFilePath); |
||||
file_path_ = reinterpret_cast<char*>(malloc(path_size)); |
||||
strlcpy(file_path_, inFilePath, path_size); |
||||
} else { |
||||
file_path_ = NULL; |
||||
} |
||||
} |
||||
|
||||
// Initializes vmaddr_, vmsize_, and slide_
|
||||
void CalculateMemoryAndVersionInfo(); |
||||
|
||||
breakpad_mach_header *header_; // our local copy of the header
|
||||
int header_size_; // mach_header plus load commands
|
||||
breakpad_mach_header *load_address_; // base address image is mapped into
|
||||
mach_vm_address_t vmaddr_; |
||||
mach_vm_size_t vmsize_; |
||||
ptrdiff_t slide_; |
||||
uint32_t version_; // Dylib version
|
||||
char *file_path_; // path dyld used to load the image
|
||||
uintptr_t file_mod_date_; // time_t of image file
|
||||
|
||||
mach_port_t task_; |
||||
}; |
||||
|
||||
//==============================================================================
|
||||
// DynamicImageRef is just a simple wrapper for a pointer to
|
||||
// DynamicImage. The reason we use it instead of a simple typedef is so
|
||||
// that we can use stl::sort() on a vector of DynamicImageRefs
|
||||
// and simple class pointers can't implement operator<().
|
||||
//
|
||||
class DynamicImageRef { |
||||
public: |
||||
explicit DynamicImageRef(DynamicImage *inP) : p(inP) {} |
||||
// The copy constructor is required by STL
|
||||
DynamicImageRef(const DynamicImageRef &inRef) : p(inRef.p) {} |
||||
|
||||
bool operator<(const DynamicImageRef &inRef) const { |
||||
return (*const_cast<DynamicImageRef*>(this)->p) |
||||
< (*const_cast<DynamicImageRef&>(inRef).p); |
||||
} |
||||
|
||||
bool operator==(const DynamicImageRef &inInfo) const { |
||||
return (*const_cast<DynamicImageRef*>(this)->p).GetLoadAddress() == |
||||
(*const_cast<DynamicImageRef&>(inInfo)).GetLoadAddress(); |
||||
} |
||||
|
||||
// Be just like DynamicImage*
|
||||
DynamicImage *operator->() {return p;} |
||||
operator DynamicImage*() {return p;} |
||||
|
||||
private: |
||||
DynamicImage *p; |
||||
}; |
||||
|
||||
//==============================================================================
|
||||
// An object of type DynamicImages may be created to allow introspection of
|
||||
// an arbitrary task's dynamically loaded mach-o binaries. This makes the
|
||||
// assumption that the current task has send rights to the target task.
|
||||
class DynamicImages { |
||||
public: |
||||
explicit DynamicImages(mach_port_t task); |
||||
|
||||
~DynamicImages() { |
||||
for (int i = 0; i < (int)image_list_.size(); ++i) { |
||||
delete image_list_[i]; |
||||
} |
||||
} |
||||
|
||||
// Returns the number of dynamically loaded mach-o images.
|
||||
int GetImageCount() const {return image_list_.size();} |
||||
|
||||
// Returns an individual image.
|
||||
DynamicImage *GetImage(int i) { |
||||
if (i < (int)image_list_.size()) { |
||||
return image_list_[i]; |
||||
} |
||||
return NULL; |
||||
} |
||||
|
||||
// Returns the image corresponding to the main executable.
|
||||
DynamicImage *GetExecutableImage(); |
||||
int GetExecutableImageIndex(); |
||||
|
||||
// Returns the task which we're looking at.
|
||||
mach_port_t GetTask() const {return task_;} |
||||
|
||||
// Debugging
|
||||
void Print() { |
||||
for (int i = 0; i < (int)image_list_.size(); ++i) { |
||||
image_list_[i]->Print(); |
||||
} |
||||
} |
||||
|
||||
void TestPrint() { |
||||
const breakpad_mach_header *header; |
||||
for (int i = 0; i < (int)image_list_.size(); ++i) { |
||||
printf("dyld: %p: name = %s\n", _dyld_get_image_header(i), |
||||
_dyld_get_image_name(i) ); |
||||
|
||||
const void *imageHeader = _dyld_get_image_header(i); |
||||
header = reinterpret_cast<const breakpad_mach_header*>(imageHeader); |
||||
|
||||
MachHeader(*header).Print(); |
||||
} |
||||
} |
||||
|
||||
private: |
||||
bool IsOurTask() {return task_ == mach_task_self();} |
||||
|
||||
// Initialization
|
||||
void ReadImageInfoForTask(); |
||||
void* GetDyldAllImageInfosPointer(); |
||||
|
||||
mach_port_t task_; |
||||
vector<DynamicImageRef> image_list_; |
||||
}; |
||||
|
||||
// Returns a malloced block containing the contents of memory at a particular
|
||||
// location in another task.
|
||||
void* ReadTaskMemory(task_port_t target_task, |
||||
const void* address, |
||||
size_t len, |
||||
kern_return_t *kr); |
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // CLIENT_MAC_HANDLER_DYNAMIC_IMAGES_H__
|
@ -0,0 +1,212 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// exception_handler.h: MacOS exception handler
|
||||
// This class can install a Mach exception port handler to trap most common
|
||||
// programming errors. If an exception occurs, a minidump file will be
|
||||
// generated which contains detailed information about the process and the
|
||||
// exception.
|
||||
|
||||
#ifndef CLIENT_MAC_HANDLER_EXCEPTION_HANDLER_H__ |
||||
#define CLIENT_MAC_HANDLER_EXCEPTION_HANDLER_H__ |
||||
|
||||
#include <mach/mach.h> |
||||
|
||||
#include <string> |
||||
|
||||
namespace google_breakpad { |
||||
|
||||
using std::string; |
||||
|
||||
struct ExceptionParameters; |
||||
|
||||
class ExceptionHandler { |
||||
public: |
||||
// A callback function to run before Breakpad performs any substantial
|
||||
// processing of an exception. A FilterCallback is called before writing
|
||||
// a minidump. context is the parameter supplied by the user as
|
||||
// callback_context when the handler was created.
|
||||
//
|
||||
// If a FilterCallback returns true, Breakpad will continue processing,
|
||||
// attempting to write a minidump. If a FilterCallback returns false, Breakpad
|
||||
// will immediately report the exception as unhandled without writing a
|
||||
// minidump, allowing another handler the opportunity to handle it.
|
||||
typedef bool (*FilterCallback)(void *context); |
||||
|
||||
// A callback function to run after the minidump has been written.
|
||||
// |minidump_id| is a unique id for the dump, so the minidump
|
||||
// file is <dump_dir>/<minidump_id>.dmp.
|
||||
// |context| is the value passed into the constructor.
|
||||
// |succeeded| indicates whether a minidump file was successfully written.
|
||||
// Return true if the exception was fully handled and breakpad should exit.
|
||||
// Return false to allow any other exception handlers to process the
|
||||
// exception.
|
||||
typedef bool (*MinidumpCallback)(const char *dump_dir, |
||||
const char *minidump_id, |
||||
void *context, bool succeeded); |
||||
|
||||
// A callback function which will be called directly if an exception occurs.
|
||||
// This bypasses the minidump file writing and simply gives the client
|
||||
// the exception information.
|
||||
typedef bool (*DirectCallback)( void *context, |
||||
int exception_type, |
||||
int exception_code, |
||||
mach_port_t thread_name); |
||||
|
||||
// Creates a new ExceptionHandler instance to handle writing minidumps.
|
||||
// Minidump files will be written to dump_path, and the optional callback
|
||||
// is called after writing the dump file, as described above.
|
||||
// If install_handler is true, then a minidump will be written whenever
|
||||
// an unhandled exception occurs. If it is false, minidumps will only
|
||||
// be written when WriteMinidump is called.
|
||||
ExceptionHandler(const string &dump_path, |
||||
FilterCallback filter, MinidumpCallback callback, |
||||
void *callback_context, bool install_handler); |
||||
|
||||
// A special constructor if we want to bypass minidump writing and
|
||||
// simply get a callback with the exception information.
|
||||
ExceptionHandler(DirectCallback callback, |
||||
void *callback_context, |
||||
bool install_handler); |
||||
|
||||
~ExceptionHandler(); |
||||
|
||||
// Get and set the minidump path.
|
||||
string dump_path() const { return dump_path_; } |
||||
void set_dump_path(const string &dump_path) { |
||||
dump_path_ = dump_path; |
||||
dump_path_c_ = dump_path_.c_str(); |
||||
UpdateNextID(); // Necessary to put dump_path_ in next_minidump_path_.
|
||||
} |
||||
|
||||
// Writes a minidump immediately. This can be used to capture the
|
||||
// execution state independently of a crash. Returns true on success.
|
||||
bool WriteMinidump(); |
||||
|
||||
// Convenience form of WriteMinidump which does not require an
|
||||
// ExceptionHandler instance.
|
||||
static bool WriteMinidump(const string &dump_path, MinidumpCallback callback, |
||||
void *callback_context); |
||||
|
||||
private: |
||||
// Install the mach exception handler
|
||||
bool InstallHandler(); |
||||
|
||||
// Uninstall the mach exception handler (if any)
|
||||
bool UninstallHandler(bool in_exception); |
||||
|
||||
// Setup the handler thread, and if |install_handler| is true, install the
|
||||
// mach exception port handler
|
||||
bool Setup(bool install_handler); |
||||
|
||||
// Uninstall the mach exception handler (if any) and terminate the helper
|
||||
// thread
|
||||
bool Teardown(); |
||||
|
||||
// Send an "empty" mach message to the exception handler. Return true on
|
||||
// success, false otherwise
|
||||
bool SendEmptyMachMessage(); |
||||
|
||||
// All minidump writing goes through this one routine
|
||||
bool WriteMinidumpWithException(int exception_type, int exception_code, |
||||
mach_port_t thread_name); |
||||
|
||||
// When installed, this static function will be call from a newly created
|
||||
// pthread with |this| as the argument
|
||||
static void *WaitForMessage(void *exception_handler_class); |
||||
|
||||
// disallow copy ctor and operator=
|
||||
explicit ExceptionHandler(const ExceptionHandler &); |
||||
void operator=(const ExceptionHandler &); |
||||
|
||||
// Generates a new ID and stores it in next_minidump_id_, and stores the
|
||||
// path of the next minidump to be written in next_minidump_path_.
|
||||
void UpdateNextID(); |
||||
|
||||
// These functions will suspend/resume all threads except for the
|
||||
// reporting thread
|
||||
bool SuspendThreads(); |
||||
bool ResumeThreads(); |
||||
|
||||
// The destination directory for the minidump
|
||||
string dump_path_; |
||||
|
||||
// The basename of the next minidump w/o extension
|
||||
string next_minidump_id_; |
||||
|
||||
// The full path to the next minidump to be written, including extension
|
||||
string next_minidump_path_; |
||||
|
||||
// Pointers to the UTF-8 versions of above
|
||||
const char *dump_path_c_; |
||||
const char *next_minidump_id_c_; |
||||
const char *next_minidump_path_c_; |
||||
|
||||
// The callback function and pointer to be passed back after the minidump
|
||||
// has been written
|
||||
FilterCallback filter_; |
||||
MinidumpCallback callback_; |
||||
void *callback_context_; |
||||
|
||||
// The callback function to be passed back when we don't want a minidump
|
||||
// file to be written
|
||||
DirectCallback directCallback_; |
||||
|
||||
// The thread that is created for the handler
|
||||
pthread_t handler_thread_; |
||||
|
||||
// The port that is waiting on an exception message to be sent, if the
|
||||
// handler is installed
|
||||
mach_port_t handler_port_; |
||||
|
||||
// These variables save the previous exception handler's data so that it
|
||||
// can be re-installed when this handler is uninstalled
|
||||
ExceptionParameters *previous_; |
||||
|
||||
// True, if we've installed the exception handler
|
||||
bool installed_exception_handler_; |
||||
|
||||
// True, if we're in the process of uninstalling the exception handler and
|
||||
// the thread.
|
||||
bool is_in_teardown_; |
||||
|
||||
// Save the last result of the last minidump
|
||||
bool last_minidump_write_result_; |
||||
|
||||
// A mutex for use when writing out a minidump that was requested on a
|
||||
// thread other than the exception handler.
|
||||
pthread_mutex_t minidump_write_mutex_; |
||||
|
||||
// True, if we're using the mutext to indicate when mindump writing occurs
|
||||
bool use_minidump_write_mutex_; |
||||
}; |
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // CLIENT_MAC_HANDLER_EXCEPTION_HANDLER_H__
|
@ -0,0 +1,157 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// minidump_generator.h: Create a minidump of the current MacOS process.
|
||||
|
||||
#ifndef CLIENT_MAC_GENERATOR_MINIDUMP_GENERATOR_H__ |
||||
#define CLIENT_MAC_GENERATOR_MINIDUMP_GENERATOR_H__ |
||||
|
||||
#include <mach/mach.h> |
||||
|
||||
#include <string> |
||||
|
||||
#include "client/minidump_file_writer.h" |
||||
#include "google_breakpad/common/minidump_format.h" |
||||
#include "common/mac/macho_utilities.h" |
||||
|
||||
#include "dynamic_images.h" |
||||
|
||||
namespace google_breakpad { |
||||
|
||||
using std::string; |
||||
|
||||
#if TARGET_CPU_X86_64 || TARGET_CPU_PPC64 |
||||
#define TOP_OF_THREAD0_STACK 0x00007fff5fbff000 |
||||
#else |
||||
#define TOP_OF_THREAD0_STACK 0xbffff000 |
||||
#endif |
||||
|
||||
#if TARGET_CPU_X86_64 |
||||
typedef x86_thread_state64_t breakpad_thread_state_t; |
||||
typedef MDRawContextAMD64 MinidumpContext; |
||||
#elif TARGET_CPU_X86 |
||||
typedef i386_thread_state_t breakpad_thread_state_t; |
||||
typedef MDRawContextX86 MinidumpContext; |
||||
#elif TARGET_CPU_PPC64 |
||||
typedef ppc_thread_state64_t breakpad_thread_state_t; |
||||
typedef MDRawContextPPC64 MinidumpContext; |
||||
#elif TARGET_CPU_PPC |
||||
typedef ppc_thread_state_t breakpad_thread_state_t; |
||||
typedef MDRawContextPPC MinidumpContext; |
||||
#endif |
||||
|
||||
// Creates a minidump file of the current process. If there is exception data,
|
||||
// use SetExceptionInformation() to add this to the minidump. The minidump
|
||||
// file is generated by the Write() function.
|
||||
// Usage:
|
||||
// MinidumpGenerator minidump();
|
||||
// minidump.Write("/tmp/minidump");
|
||||
//
|
||||
class MinidumpGenerator { |
||||
public: |
||||
MinidumpGenerator(); |
||||
MinidumpGenerator(mach_port_t crashing_task, mach_port_t handler_thread); |
||||
|
||||
~MinidumpGenerator(); |
||||
|
||||
// Return <dir>/<unique_name>.dmp
|
||||
// Sets |unique_name| (if requested) to the unique name for the minidump
|
||||
static string UniqueNameInDirectory(const string &dir, string *unique_name); |
||||
|
||||
// Write out the minidump into |path|
|
||||
// All of the components of |path| must exist and be writable
|
||||
// Return true if successful, false otherwise
|
||||
bool Write(const char *path); |
||||
|
||||
// Specify some exception information, if applicable
|
||||
void SetExceptionInformation(int type, int code, mach_port_t thread_name) { |
||||
exception_type_ = type; |
||||
exception_code_ = code; |
||||
exception_thread_ = thread_name; |
||||
} |
||||
|
||||
// Gather system information. This should be call at least once before using
|
||||
// the MinidumpGenerator class.
|
||||
static void GatherSystemInformation(); |
||||
|
||||
private: |
||||
typedef bool (MinidumpGenerator::*WriteStreamFN)(MDRawDirectory *); |
||||
|
||||
// Stream writers
|
||||
bool WriteThreadListStream(MDRawDirectory *thread_list_stream); |
||||
bool WriteExceptionStream(MDRawDirectory *exception_stream); |
||||
bool WriteSystemInfoStream(MDRawDirectory *system_info_stream); |
||||
bool WriteModuleListStream(MDRawDirectory *module_list_stream); |
||||
bool WriteMiscInfoStream(MDRawDirectory *misc_info_stream); |
||||
bool WriteBreakpadInfoStream(MDRawDirectory *breakpad_info_stream); |
||||
|
||||
// Helpers
|
||||
u_int64_t CurrentPCForStack(breakpad_thread_state_data_t state); |
||||
bool WriteStackFromStartAddress(mach_vm_address_t start_addr, |
||||
MDMemoryDescriptor *stack_location); |
||||
bool WriteStack(breakpad_thread_state_data_t state, |
||||
MDMemoryDescriptor *stack_location); |
||||
bool WriteContext(breakpad_thread_state_data_t state, |
||||
MDLocationDescriptor *register_location); |
||||
bool WriteThreadStream(mach_port_t thread_id, MDRawThread *thread); |
||||
bool WriteCVRecord(MDRawModule *module, int cpu_type,
|
||||
const char *module_path); |
||||
bool WriteModuleStream(unsigned int index, MDRawModule *module); |
||||
|
||||
size_t CalculateStackSize(mach_vm_address_t start_addr); |
||||
|
||||
int FindExecutableModule(); |
||||
|
||||
// disallow copy ctor and operator=
|
||||
explicit MinidumpGenerator(const MinidumpGenerator &); |
||||
void operator=(const MinidumpGenerator &); |
||||
|
||||
// Use this writer to put the data to disk
|
||||
MinidumpFileWriter writer_; |
||||
|
||||
// Exception information
|
||||
int exception_type_; |
||||
int exception_code_; |
||||
mach_port_t exception_thread_; |
||||
mach_port_t crashing_task_; |
||||
mach_port_t handler_thread_; |
||||
|
||||
// System information
|
||||
static char build_string_[16]; |
||||
static int os_major_version_; |
||||
static int os_minor_version_; |
||||
static int os_build_number_; |
||||
|
||||
// Information about dynamically loaded code
|
||||
DynamicImages *dynamic_images_; |
||||
}; |
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // CLIENT_MAC_GENERATOR_MINIDUMP_GENERATOR_H__
|
@ -0,0 +1,85 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// ProtectedMemoryAllocator
|
||||
//
|
||||
// A very simple allocator class which allows allocation, but not deallocation.
|
||||
// The allocations can be made read-only with the Protect() method.
|
||||
// This class is NOT useful as a general-purpose memory allocation system,
|
||||
// since it does not allow deallocation. It is useful to use for a group
|
||||
// of allocations which are created in the same time-frame and destroyed
|
||||
// in the same time-frame. It is useful for making allocations of memory
|
||||
// which will not need to change often once initialized. This memory can then
|
||||
// be protected from memory smashers by calling the Protect() method.
|
||||
|
||||
#ifndef PROTECTED_MEMORY_ALLOCATOR_H__ |
||||
#define PROTECTED_MEMORY_ALLOCATOR_H__ |
||||
|
||||
#include <mach/mach.h> |
||||
|
||||
//
|
||||
class ProtectedMemoryAllocator { |
||||
public: |
||||
ProtectedMemoryAllocator(vm_size_t pool_size);
|
||||
~ProtectedMemoryAllocator(); |
||||
|
||||
// Returns a pointer to an allocation of size n within the pool.
|
||||
// Fails by returning NULL is no more space is available.
|
||||
// Please note that the pointers returned from this method should not
|
||||
// be freed in any way (for example by calling free() on them ).
|
||||
char * Allocate(size_t n); |
||||
|
||||
// Returns the base address of the allocation pool.
|
||||
char * GetBaseAddress() { return (char*)base_address_; } |
||||
|
||||
// Returns the size of the allocation pool, including allocated
|
||||
// plus free space.
|
||||
vm_size_t GetTotalSize() { return pool_size_; } |
||||
|
||||
// Returns the number of bytes already allocated in the pool.
|
||||
vm_size_t GetAllocatedSize() { return next_alloc_offset_; } |
||||
|
||||
// Returns the number of bytes available for allocation.
|
||||
vm_size_t GetFreeSize() { return pool_size_ - next_alloc_offset_; } |
||||
|
||||
// Makes the entire allocation pool read-only including, of course,
|
||||
// all allocations made from the pool.
|
||||
kern_return_t Protect();
|
||||
|
||||
// Makes the entire allocation pool read/write.
|
||||
kern_return_t Unprotect();
|
||||
|
||||
private: |
||||
vm_size_t pool_size_; |
||||
vm_address_t base_address_; |
||||
int next_alloc_offset_; |
||||
bool valid_; |
||||
}; |
||||
|
||||
#endif // PROTECTED_MEMORY_ALLOCATOR_H__
|
@ -0,0 +1,94 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// minidump_file_writer-inl.h: Minidump file writer implementation.
|
||||
//
|
||||
// See minidump_file_writer.h for documentation.
|
||||
|
||||
#ifndef CLIENT_MINIDUMP_FILE_WRITER_INL_H__ |
||||
#define CLIENT_MINIDUMP_FILE_WRITER_INL_H__ |
||||
|
||||
#include <assert.h> |
||||
|
||||
#include "client/minidump_file_writer.h" |
||||
#include "google_breakpad/common/minidump_size.h" |
||||
|
||||
namespace google_breakpad { |
||||
|
||||
template<typename MDType> |
||||
inline bool TypedMDRVA<MDType>::Allocate() { |
||||
allocation_state_ = SINGLE_OBJECT; |
||||
return UntypedMDRVA::Allocate(minidump_size<MDType>::size()); |
||||
} |
||||
|
||||
template<typename MDType> |
||||
inline bool TypedMDRVA<MDType>::Allocate(size_t additional) { |
||||
allocation_state_ = SINGLE_OBJECT; |
||||
return UntypedMDRVA::Allocate(minidump_size<MDType>::size() + additional); |
||||
} |
||||
|
||||
template<typename MDType> |
||||
inline bool TypedMDRVA<MDType>::AllocateArray(size_t count) { |
||||
assert(count); |
||||
allocation_state_ = ARRAY; |
||||
return UntypedMDRVA::Allocate(minidump_size<MDType>::size() * count); |
||||
} |
||||
|
||||
template<typename MDType> |
||||
inline bool TypedMDRVA<MDType>::AllocateObjectAndArray(unsigned int count, |
||||
size_t size) { |
||||
assert(count && size); |
||||
allocation_state_ = SINGLE_OBJECT_WITH_ARRAY; |
||||
return UntypedMDRVA::Allocate(minidump_size<MDType>::size() + count * size); |
||||
} |
||||
|
||||
template<typename MDType> |
||||
inline bool TypedMDRVA<MDType>::CopyIndex(unsigned int index, MDType *item) { |
||||
assert(allocation_state_ == ARRAY); |
||||
return writer_->Copy(position_ + index * minidump_size<MDType>::size(), item, |
||||
minidump_size<MDType>::size()); |
||||
} |
||||
|
||||
template<typename MDType> |
||||
inline bool TypedMDRVA<MDType>::CopyIndexAfterObject(unsigned int index, |
||||
const void *src,
|
||||
size_t size) { |
||||
assert(allocation_state_ == SINGLE_OBJECT_WITH_ARRAY); |
||||
return writer_->Copy(position_ + minidump_size<MDType>::size() + index * size, |
||||
src, size); |
||||
} |
||||
|
||||
template<typename MDType> |
||||
inline bool TypedMDRVA<MDType>::Flush() { |
||||
return writer_->Copy(position_, &data_, minidump_size<MDType>::size()); |
||||
} |
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // CLIENT_MINIDUMP_FILE_WRITER_INL_H__
|
@ -0,0 +1,250 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// minidump_file_writer.h: Implements file-based minidump generation. It's
|
||||
// intended to be used with the Google Breakpad open source crash handling
|
||||
// project.
|
||||
|
||||
#ifndef CLIENT_MINIDUMP_FILE_WRITER_H__ |
||||
#define CLIENT_MINIDUMP_FILE_WRITER_H__ |
||||
|
||||
#include <string> |
||||
|
||||
#include "google_breakpad/common/minidump_format.h" |
||||
|
||||
namespace google_breakpad { |
||||
|
||||
class UntypedMDRVA; |
||||
template<typename MDType> class TypedMDRVA; |
||||
|
||||
// The user of this class can Open() a file and add minidump streams, data, and
|
||||
// strings using the definitions in minidump_format.h. Since this class is
|
||||
// expected to be used in a situation where the current process may be
|
||||
// damaged, it will not allocate heap memory.
|
||||
// Sample usage:
|
||||
// MinidumpFileWriter writer;
|
||||
// writer.Open("/tmp/minidump.dmp");
|
||||
// TypedMDRVA<MDRawHeader> header(&writer_);
|
||||
// header.Allocate();
|
||||
// header->get()->signature = MD_HEADER_SIGNATURE;
|
||||
// :
|
||||
// writer.Close();
|
||||
class MinidumpFileWriter { |
||||
public: |
||||
// Invalid MDRVA (Minidump Relative Virtual Address)
|
||||
// returned on failed allocation
|
||||
static const MDRVA kInvalidMDRVA; |
||||
|
||||
MinidumpFileWriter(); |
||||
~MinidumpFileWriter(); |
||||
|
||||
// Open |path| as the destination of the minidump data. Any existing file
|
||||
// will be overwritten.
|
||||
// Return true on success, or false on failure
|
||||
bool Open(const char *path); |
||||
|
||||
// Close the current file
|
||||
// Return true on success, or false on failure
|
||||
bool Close(); |
||||
|
||||
// Copy the contents of |str| to a MDString and write it to the file.
|
||||
// |str| is expected to be either UTF-16 or UTF-32 depending on the size
|
||||
// of wchar_t.
|
||||
// Maximum |length| of characters to copy from |str|, or specify 0 to use the
|
||||
// entire NULL terminated string. Copying will stop at the first NULL.
|
||||
// |location| the allocated location
|
||||
// Return true on success, or false on failure
|
||||
bool WriteString(const wchar_t *str, unsigned int length, |
||||
MDLocationDescriptor *location); |
||||
|
||||
// Same as above, except with |str| as a UTF-8 string
|
||||
bool WriteString(const char *str, unsigned int length, |
||||
MDLocationDescriptor *location); |
||||
|
||||
// Write |size| bytes starting at |src| into the current position.
|
||||
// Return true on success and set |output| to position, or false on failure
|
||||
bool WriteMemory(const void *src, size_t size, MDMemoryDescriptor *output); |
||||
|
||||
// Copies |size| bytes from |src| to |position|
|
||||
// Return true on success, or false on failure
|
||||
bool Copy(MDRVA position, const void *src, ssize_t size); |
||||
|
||||
// Return the current position for writing to the minidump
|
||||
inline MDRVA position() const { return position_; } |
||||
|
||||
private: |
||||
friend class UntypedMDRVA; |
||||
|
||||
// Allocates an area of |size| bytes.
|
||||
// Returns the position of the allocation, or kInvalidMDRVA if it was
|
||||
// unable to allocate the bytes.
|
||||
MDRVA Allocate(size_t size); |
||||
|
||||
// The file descriptor for the output file
|
||||
int file_; |
||||
|
||||
// Current position in buffer
|
||||
MDRVA position_; |
||||
|
||||
// Current allocated size
|
||||
size_t size_; |
||||
|
||||
// Copy |length| characters from |str| to |mdstring|. These are distinct
|
||||
// because the underlying MDString is a UTF-16 based string. The wchar_t
|
||||
// variant may need to create a MDString that has more characters than the
|
||||
// source |str|, whereas the UTF-8 variant may coalesce characters to form
|
||||
// a single UTF-16 character.
|
||||
bool CopyStringToMDString(const wchar_t *str, unsigned int length, |
||||
TypedMDRVA<MDString> *mdstring); |
||||
bool CopyStringToMDString(const char *str, unsigned int length, |
||||
TypedMDRVA<MDString> *mdstring); |
||||
|
||||
// The common templated code for writing a string
|
||||
template <typename CharType> |
||||
bool WriteStringCore(const CharType *str, unsigned int length, |
||||
MDLocationDescriptor *location); |
||||
}; |
||||
|
||||
// Represents an untyped allocated chunk
|
||||
class UntypedMDRVA { |
||||
public: |
||||
explicit UntypedMDRVA(MinidumpFileWriter *writer) |
||||
: writer_(writer), |
||||
position_(writer->position()), |
||||
size_(0) {} |
||||
|
||||
// Allocates |size| bytes. Must not call more than once.
|
||||
// Return true on success, or false on failure
|
||||
bool Allocate(size_t size); |
||||
|
||||
// Returns the current position or kInvalidMDRVA if allocation failed
|
||||
inline MDRVA position() const { return position_; } |
||||
|
||||
// Number of bytes allocated
|
||||
inline size_t size() const { return size_; } |
||||
|
||||
// Return size and position
|
||||
inline MDLocationDescriptor location() const { |
||||
MDLocationDescriptor location = { size_, position_ }; |
||||
return location; |
||||
} |
||||
|
||||
// Copy |size| bytes starting at |src| into the minidump at |position|
|
||||
// Return true on success, or false on failure
|
||||
bool Copy(MDRVA position, const void *src, size_t size); |
||||
|
||||
// Copy |size| bytes from |src| to the current position
|
||||
inline bool Copy(const void *src, size_t size) { |
||||
return Copy(position_, src, size); |
||||
} |
||||
|
||||
protected: |
||||
// Writer we associate with
|
||||
MinidumpFileWriter *writer_; |
||||
|
||||
// Position of the start of the data
|
||||
MDRVA position_; |
||||
|
||||
// Allocated size
|
||||
size_t size_; |
||||
}; |
||||
|
||||
// Represents a Minidump object chunk. Additional memory can be allocated at
|
||||
// the end of the object as a:
|
||||
// - single allocation
|
||||
// - Array of MDType objects
|
||||
// - A MDType object followed by an array
|
||||
template<typename MDType> |
||||
class TypedMDRVA : public UntypedMDRVA { |
||||
public: |
||||
// Constructs an unallocated MDRVA
|
||||
explicit TypedMDRVA(MinidumpFileWriter *writer) |
||||
: UntypedMDRVA(writer), |
||||
data_(), |
||||
allocation_state_(UNALLOCATED) {} |
||||
|
||||
inline ~TypedMDRVA() { |
||||
// Ensure that the data_ object is written out
|
||||
if (allocation_state_ != ARRAY) |
||||
Flush(); |
||||
} |
||||
|
||||
// Address of object data_ of MDType. This is not declared const as the
|
||||
// typical usage will be to access the underlying |data_| object as to
|
||||
// alter its contents.
|
||||
MDType *get() { return &data_; } |
||||
|
||||
// Allocates minidump_size<MDType>::size() bytes.
|
||||
// Must not call more than once.
|
||||
// Return true on success, or false on failure
|
||||
bool Allocate(); |
||||
|
||||
// Allocates minidump_size<MDType>::size() + |additional| bytes.
|
||||
// Must not call more than once.
|
||||
// Return true on success, or false on failure
|
||||
bool Allocate(size_t additional); |
||||
|
||||
// Allocate an array of |count| elements of MDType.
|
||||
// Must not call more than once.
|
||||
// Return true on success, or false on failure
|
||||
bool AllocateArray(size_t count); |
||||
|
||||
// Allocate an array of |count| elements of |size| after object of MDType
|
||||
// Must not call more than once.
|
||||
// Return true on success, or false on failure
|
||||
bool AllocateObjectAndArray(unsigned int count, size_t size); |
||||
|
||||
// Copy |item| to |index|
|
||||
// Must have been allocated using AllocateArray().
|
||||
// Return true on success, or false on failure
|
||||
bool CopyIndex(unsigned int index, MDType *item); |
||||
|
||||
// Copy |size| bytes starting at |str| to |index|
|
||||
// Must have been allocated using AllocateObjectAndArray().
|
||||
// Return true on success, or false on failure
|
||||
bool CopyIndexAfterObject(unsigned int index, const void *src, size_t size); |
||||
|
||||
// Write data_
|
||||
bool Flush(); |
||||
|
||||
private: |
||||
enum AllocationState { |
||||
UNALLOCATED = 0, |
||||
SINGLE_OBJECT, |
||||
ARRAY, |
||||
SINGLE_OBJECT_WITH_ARRAY |
||||
}; |
||||
|
||||
MDType data_; |
||||
AllocationState allocation_state_; |
||||
}; |
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // CLIENT_MINIDUMP_FILE_WRITER_H__
|
@ -0,0 +1,63 @@ |
||||
// Copyright (c) 2008, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef CLIENT_WINDOWS_COMMON_AUTO_CRITICAL_SECTION_H__ |
||||
#define CLIENT_WINDOWS_COMMON_AUTO_CRITICAL_SECTION_H__ |
||||
|
||||
#include <Windows.h> |
||||
|
||||
namespace google_breakpad { |
||||
|
||||
// Automatically enters the critical section in the constructor and leaves
|
||||
// the critical section in the destructor.
|
||||
class AutoCriticalSection { |
||||
public: |
||||
// Creates a new instance with the given critical section object
|
||||
// and enters the critical section immediately.
|
||||
explicit AutoCriticalSection(CRITICAL_SECTION* cs) : cs_(cs) { |
||||
assert(cs_); |
||||
EnterCriticalSection(cs_); |
||||
} |
||||
|
||||
// Destructor: leaves the critical section.
|
||||
~AutoCriticalSection() { |
||||
LeaveCriticalSection(cs_); |
||||
} |
||||
|
||||
private: |
||||
// Disable copy ctor and operator=.
|
||||
AutoCriticalSection(const AutoCriticalSection&); |
||||
AutoCriticalSection& operator=(const AutoCriticalSection&); |
||||
|
||||
CRITICAL_SECTION* cs_; |
||||
}; |
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // CLIENT_WINDOWS_COMMON_AUTO_CRITICAL_SECTION_H__
|
@ -0,0 +1,179 @@ |
||||
// Copyright (c) 2008, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef CLIENT_WINDOWS_COMMON_IPC_PROTOCOL_H__ |
||||
#define CLIENT_WINDOWS_COMMON_IPC_PROTOCOL_H__ |
||||
|
||||
#include <Windows.h> |
||||
#include <DbgHelp.h> |
||||
#include <string> |
||||
#include <utility> |
||||
#include "common/windows/string_utils-inl.h" |
||||
#include "google_breakpad/common/minidump_format.h" |
||||
|
||||
namespace google_breakpad { |
||||
|
||||
// Name/value pair for custom client information.
|
||||
struct CustomInfoEntry { |
||||
// Maximum length for name and value for client custom info.
|
||||
static const int kNameMaxLength = 64; |
||||
static const int kValueMaxLength = 64; |
||||
|
||||
CustomInfoEntry() { |
||||
// Putting name and value in initializer list makes VC++ show warning 4351.
|
||||
set_name(NULL); |
||||
set_value(NULL); |
||||
} |
||||
|
||||
CustomInfoEntry(const wchar_t* name_arg, const wchar_t* value_arg) { |
||||
set_name(name_arg); |
||||
set_value(value_arg); |
||||
} |
||||
|
||||
void set_name(const wchar_t* name_arg) { |
||||
if (!name_arg) { |
||||
name[0] = L'\0'; |
||||
return; |
||||
} |
||||
WindowsStringUtils::safe_wcscpy(name, kNameMaxLength, name_arg); |
||||
} |
||||
|
||||
void set_value(const wchar_t* value_arg) { |
||||
if (!value_arg) { |
||||
value[0] = L'\0'; |
||||
return; |
||||
} |
||||
|
||||
WindowsStringUtils::safe_wcscpy(value, kValueMaxLength, value_arg); |
||||
} |
||||
|
||||
void set(const wchar_t* name_arg, const wchar_t* value_arg) { |
||||
set_name(name_arg); |
||||
set_value(value_arg); |
||||
} |
||||
|
||||
wchar_t name[kNameMaxLength]; |
||||
wchar_t value[kValueMaxLength]; |
||||
}; |
||||
|
||||
// Constants for the protocol between client and the server.
|
||||
|
||||
// Tags sent with each message indicating the purpose of
|
||||
// the message.
|
||||
enum MessageTag { |
||||
MESSAGE_TAG_NONE = 0, |
||||
MESSAGE_TAG_REGISTRATION_REQUEST = 1, |
||||
MESSAGE_TAG_REGISTRATION_RESPONSE = 2, |
||||
MESSAGE_TAG_REGISTRATION_ACK = 3 |
||||
}; |
||||
|
||||
struct CustomClientInfo { |
||||
const CustomInfoEntry* entries; |
||||
int count; |
||||
}; |
||||
|
||||
// Message structure for IPC between crash client and crash server.
|
||||
struct ProtocolMessage { |
||||
ProtocolMessage() |
||||
: tag(MESSAGE_TAG_NONE), |
||||
pid(0), |
||||
dump_type(MiniDumpNormal), |
||||
thread_id(0), |
||||
exception_pointers(NULL), |
||||
assert_info(NULL), |
||||
custom_client_info(), |
||||
dump_request_handle(NULL), |
||||
dump_generated_handle(NULL), |
||||
server_alive_handle(NULL) { |
||||
} |
||||
|
||||
// Creates an instance with the given parameters.
|
||||
ProtocolMessage(MessageTag arg_tag, |
||||
DWORD arg_pid, |
||||
MINIDUMP_TYPE arg_dump_type, |
||||
DWORD* arg_thread_id, |
||||
EXCEPTION_POINTERS** arg_exception_pointers, |
||||
MDRawAssertionInfo* arg_assert_info, |
||||
const CustomClientInfo& custom_info, |
||||
HANDLE arg_dump_request_handle, |
||||
HANDLE arg_dump_generated_handle, |
||||
HANDLE arg_server_alive) |
||||
: tag(arg_tag), |
||||
pid(arg_pid), |
||||
dump_type(arg_dump_type), |
||||
thread_id(arg_thread_id), |
||||
exception_pointers(arg_exception_pointers), |
||||
assert_info(arg_assert_info), |
||||
custom_client_info(custom_info), |
||||
dump_request_handle(arg_dump_request_handle), |
||||
dump_generated_handle(arg_dump_generated_handle), |
||||
server_alive_handle(arg_server_alive) { |
||||
} |
||||
|
||||
// Tag in the message.
|
||||
MessageTag tag; |
||||
|
||||
// Process id.
|
||||
DWORD pid; |
||||
|
||||
// Dump type requested.
|
||||
MINIDUMP_TYPE dump_type; |
||||
|
||||
// Client thread id pointer.
|
||||
DWORD* thread_id; |
||||
|
||||
// Exception information.
|
||||
EXCEPTION_POINTERS** exception_pointers; |
||||
|
||||
// Assert information in case of an invalid parameter or
|
||||
// pure call failure.
|
||||
MDRawAssertionInfo* assert_info; |
||||
|
||||
// Custom client information.
|
||||
CustomClientInfo custom_client_info; |
||||
|
||||
// Handle to signal the crash event.
|
||||
HANDLE dump_request_handle; |
||||
|
||||
// Handle to check if server is done generating crash.
|
||||
HANDLE dump_generated_handle; |
||||
|
||||
// Handle to a mutex that becomes signaled (WAIT_ABANDONED)
|
||||
// if server process goes down.
|
||||
HANDLE server_alive_handle; |
||||
|
||||
private: |
||||
// Disable copy ctor and operator=.
|
||||
ProtocolMessage(const ProtocolMessage& msg); |
||||
ProtocolMessage& operator=(const ProtocolMessage& msg); |
||||
}; |
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // CLIENT_WINDOWS_COMMON_IPC_PROTOCOL_H__
|
@ -0,0 +1,170 @@ |
||||
// Copyright (c) 2008, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef CLIENT_WINDOWS_CRASH_GENERATION_CLIENT_INFO_H__ |
||||
#define CLIENT_WINDOWS_CRASH_GENERATION_CLIENT_INFO_H__ |
||||
|
||||
#include <Windows.h> |
||||
#include <DbgHelp.h> |
||||
#include "client/windows/common/ipc_protocol.h" |
||||
#include "google_breakpad/common/minidump_format.h" |
||||
#include "processor/scoped_ptr.h" |
||||
|
||||
namespace google_breakpad { |
||||
|
||||
class CrashGenerationServer; |
||||
|
||||
// Abstraction for a crash client process.
|
||||
class ClientInfo { |
||||
public: |
||||
// Creates an instance with the given values. Gets the process
|
||||
// handle for the given process id and creates necessary event
|
||||
// objects.
|
||||
ClientInfo(CrashGenerationServer* crash_server, |
||||
DWORD pid, |
||||
MINIDUMP_TYPE dump_type, |
||||
DWORD* thread_id, |
||||
EXCEPTION_POINTERS** ex_info, |
||||
MDRawAssertionInfo* assert_info, |
||||
const CustomClientInfo& custom_client_info); |
||||
|
||||
~ClientInfo(); |
||||
|
||||
CrashGenerationServer* crash_server() const { return crash_server_; } |
||||
DWORD pid() const { return pid_; } |
||||
MINIDUMP_TYPE dump_type() const { return dump_type_; } |
||||
EXCEPTION_POINTERS** ex_info() const { return ex_info_; } |
||||
MDRawAssertionInfo* assert_info() const { return assert_info_; } |
||||
DWORD* thread_id() const { return thread_id_; } |
||||
HANDLE process_handle() const { return process_handle_; } |
||||
HANDLE dump_requested_handle() const { return dump_requested_handle_; } |
||||
HANDLE dump_generated_handle() const { return dump_generated_handle_; } |
||||
|
||||
HANDLE dump_request_wait_handle() const { |
||||
return dump_request_wait_handle_; |
||||
} |
||||
|
||||
void set_dump_request_wait_handle(HANDLE value) { |
||||
dump_request_wait_handle_ = value; |
||||
} |
||||
|
||||
HANDLE process_exit_wait_handle() const { |
||||
return process_exit_wait_handle_; |
||||
} |
||||
|
||||
void set_process_exit_wait_handle(HANDLE value) { |
||||
process_exit_wait_handle_ = value; |
||||
} |
||||
|
||||
// Unregister all waits for the client.
|
||||
bool UnregisterWaits(); |
||||
|
||||
bool Initialize(); |
||||
bool GetClientExceptionInfo(EXCEPTION_POINTERS** ex_info) const; |
||||
bool GetClientThreadId(DWORD* thread_id) const; |
||||
|
||||
// Reads the custom information from the client process address space.
|
||||
bool PopulateCustomInfo(); |
||||
|
||||
// Returns the client custom information.
|
||||
CustomClientInfo GetCustomInfo() const; |
||||
|
||||
private: |
||||
// Calcualtes the uptime for the client process, converts it to a string and
|
||||
// stores it in the last entry of client custom info.
|
||||
void SetProcessUptime(); |
||||
|
||||
// Crash generation server.
|
||||
CrashGenerationServer* crash_server_; |
||||
|
||||
// Client process ID.
|
||||
DWORD pid_; |
||||
|
||||
// Dump type requested by the client.
|
||||
MINIDUMP_TYPE dump_type_; |
||||
|
||||
// Address of an EXCEPTION_POINTERS* variable in the client
|
||||
// process address space that will point to an instance of
|
||||
// EXCEPTION_POINTERS containing information about crash.
|
||||
//
|
||||
// WARNING: Do not dereference these pointers as they are pointers
|
||||
// in the address space of another process.
|
||||
EXCEPTION_POINTERS** ex_info_; |
||||
|
||||
// Address of an instance of MDRawAssertionInfo in the client
|
||||
// process address space that will contain information about
|
||||
// non-exception related crashes like invalid parameter assertion
|
||||
// failures and pure calls.
|
||||
//
|
||||
// WARNING: Do not dereference these pointers as they are pointers
|
||||
// in the address space of another process.
|
||||
MDRawAssertionInfo* assert_info_; |
||||
|
||||
// Custom information about the client.
|
||||
CustomClientInfo custom_client_info_; |
||||
|
||||
// Contains the custom client info entries read from the client process
|
||||
// memory. This will be populated only if the method GetClientCustomInfo
|
||||
// is called.
|
||||
scoped_array<CustomInfoEntry> custom_info_entries_; |
||||
|
||||
// Address of a variable in the client process address space that
|
||||
// will contain the thread id of the crashing client thread.
|
||||
//
|
||||
// WARNING: Do not dereference these pointers as they are pointers
|
||||
// in the address space of another process.
|
||||
DWORD* thread_id_; |
||||
|
||||
// Client process handle.
|
||||
HANDLE process_handle_; |
||||
|
||||
// Dump request event handle.
|
||||
HANDLE dump_requested_handle_; |
||||
|
||||
// Dump generated event handle.
|
||||
HANDLE dump_generated_handle_; |
||||
|
||||
// Wait handle for dump request event.
|
||||
HANDLE dump_request_wait_handle_; |
||||
|
||||
// Wait handle for process exit event.
|
||||
HANDLE process_exit_wait_handle_; |
||||
|
||||
// Time when the client process started. It is used to determine the uptime
|
||||
// for the client process when it signals a crash.
|
||||
FILETIME start_time_; |
||||
|
||||
// Disallow copy ctor and operator=.
|
||||
ClientInfo(const ClientInfo& client_info); |
||||
ClientInfo& operator=(const ClientInfo& client_info); |
||||
}; |
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // CLIENT_WINDOWS_CRASH_GENERATION_CLIENT_INFO_H__
|
@ -0,0 +1,159 @@ |
||||
// Copyright (c) 2008, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H__ |
||||
#define CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H__ |
||||
|
||||
#include <windows.h> |
||||
#include <dbghelp.h> |
||||
#include <string> |
||||
#include <utility> |
||||
#include "client/windows/common/ipc_protocol.h" |
||||
#include "processor/scoped_ptr.h" |
||||
|
||||
namespace google_breakpad { |
||||
|
||||
struct CustomClientInfo; |
||||
|
||||
// Abstraction of client-side implementation of out of process
|
||||
// crash generation.
|
||||
//
|
||||
// The process that desires to have out-of-process crash dump
|
||||
// generation service can use this class in the following way:
|
||||
//
|
||||
// * Create an instance.
|
||||
// * Call Register method so that the client tries to register
|
||||
// with the server process and check the return value. If
|
||||
// registration is not successful, out-of-process crash dump
|
||||
// generation will not be available
|
||||
// * Request dump generation by calling either of the two
|
||||
// overloaded RequestDump methods - one in case of exceptions
|
||||
// and the other in case of assertion failures
|
||||
//
|
||||
// Note that it is the responsibility of the client code of
|
||||
// this class to set the unhandled exception filter with the
|
||||
// system by calling the SetUnhandledExceptionFilter function
|
||||
// and the client code should explicitly request dump generation.
|
||||
class CrashGenerationClient { |
||||
public: |
||||
CrashGenerationClient(const wchar_t* pipe_name, |
||||
MINIDUMP_TYPE dump_type, |
||||
const CustomClientInfo* custom_info); |
||||
|
||||
~CrashGenerationClient(); |
||||
|
||||
// Registers the client process with the crash server.
|
||||
//
|
||||
// Returns true if the registration is successful; false otherwise.
|
||||
bool Register(); |
||||
|
||||
// Requests the crash server to generate a dump with the given
|
||||
// exception information.
|
||||
//
|
||||
// Returns true if the dump was successful; false otherwise. Note that
|
||||
// if the registration step was not performed or it was not successful,
|
||||
// false will be returned.
|
||||
bool RequestDump(EXCEPTION_POINTERS* ex_info); |
||||
|
||||
// Requests the crash server to generate a dump with the given
|
||||
// assertion information.
|
||||
//
|
||||
// Returns true if the dump was successful; false otherwise. Note that
|
||||
// if the registration step was not performed or it was not successful,
|
||||
// false will be returned.
|
||||
bool RequestDump(MDRawAssertionInfo* assert_info); |
||||
|
||||
private: |
||||
// Connects to the appropriate pipe and sets the pipe handle state.
|
||||
//
|
||||
// Returns the pipe handle if everything goes well; otherwise Returns NULL.
|
||||
HANDLE ConnectToServer(); |
||||
|
||||
// Performs a handshake with the server over the given pipe which should be
|
||||
// already connected to the server.
|
||||
//
|
||||
// Returns true if handshake with the server was successful; false otherwise.
|
||||
bool RegisterClient(HANDLE pipe); |
||||
|
||||
// Validates the given server response.
|
||||
bool ValidateResponse(const ProtocolMessage& msg) const; |
||||
|
||||
// Returns true if the registration step succeeded; false otherwise.
|
||||
bool IsRegistered() const; |
||||
|
||||
// Connects to the given named pipe with given parameters.
|
||||
//
|
||||
// Returns true if the connection is successful; false otherwise.
|
||||
HANDLE ConnectToPipe(const wchar_t* pipe_name, |
||||
DWORD pipe_access, |
||||
DWORD flags_attrs); |
||||
|
||||
// Signals the crash event and wait for the server to generate crash.
|
||||
bool SignalCrashEventAndWait(); |
||||
|
||||
// Pipe name to use to talk to server.
|
||||
std::wstring pipe_name_; |
||||
|
||||
// Custom client information
|
||||
CustomClientInfo custom_info_; |
||||
|
||||
// Type of dump to generate.
|
||||
MINIDUMP_TYPE dump_type_; |
||||
|
||||
// Event to signal in case of a crash.
|
||||
HANDLE crash_event_; |
||||
|
||||
// Handle to wait on after signaling a crash for the server
|
||||
// to finish generating crash dump.
|
||||
HANDLE crash_generated_; |
||||
|
||||
// Handle to a mutex that will become signaled with WAIT_ABANDONED
|
||||
// if the server process goes down.
|
||||
HANDLE server_alive_; |
||||
|
||||
// Server process id.
|
||||
DWORD server_process_id_; |
||||
|
||||
// Id of the thread that caused the crash.
|
||||
DWORD thread_id_; |
||||
|
||||
// Exception pointers for an exception crash.
|
||||
EXCEPTION_POINTERS* exception_pointers_; |
||||
|
||||
// Assertion info for an invalid parameter or pure call crash.
|
||||
MDRawAssertionInfo assert_info_; |
||||
|
||||
// Disable copy ctor and operator=.
|
||||
CrashGenerationClient(const CrashGenerationClient& crash_client); |
||||
CrashGenerationClient& operator=(const CrashGenerationClient& crash_client); |
||||
}; |
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H__
|
@ -0,0 +1,269 @@ |
||||
// Copyright (c) 2008, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_SERVER_H__ |
||||
#define CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_SERVER_H__ |
||||
|
||||
#include <list> |
||||
#include <string> |
||||
#include "client/windows/common/ipc_protocol.h" |
||||
#include "client/windows/crash_generation/client_info.h" |
||||
#include "client/windows/crash_generation/minidump_generator.h" |
||||
#include "processor/scoped_ptr.h" |
||||
|
||||
namespace google_breakpad { |
||||
|
||||
// Abstraction for server side implementation of out-of-process crash
|
||||
// generation protocol for Windows platform only. It generates Windows
|
||||
// minidump files for client processes that request dump generation. When
|
||||
// the server is requested to start listening for clients (by calling the
|
||||
// Start method), it creates a named pipe and waits for the clients to
|
||||
// register. In response, it hands them event handles that the client can
|
||||
// signal to request dump generation. When the clients request dump
|
||||
// generation in this way, the server generates Windows minidump files.
|
||||
class CrashGenerationServer { |
||||
public: |
||||
typedef void (*OnClientConnectedCallback)(void* context, |
||||
const ClientInfo* client_info); |
||||
|
||||
typedef void (*OnClientDumpRequestCallback)(void* context, |
||||
const ClientInfo* client_info, |
||||
const std::wstring* file_path); |
||||
|
||||
typedef void (*OnClientExitedCallback)(void* context, |
||||
const ClientInfo* client_info); |
||||
|
||||
// Creates an instance with the given parameters.
|
||||
//
|
||||
// Parameter pipe_name: Name of the Windows named pipe
|
||||
// Parameter pipe_sec_attrs Security attributes to set on the pipe. Pass
|
||||
// NULL to use default security on the pipe. By default, the pipe created
|
||||
// allows Local System, Administrators and the Creator full control and
|
||||
// the Everyone group read access on the pipe.
|
||||
// Parameter connect_callback: Callback for a new client connection.
|
||||
// Parameter connect_context: Context for client connection callback.
|
||||
// Parameter crash_callback: Callback for a client crash dump request.
|
||||
// Parameter crash_context: Context for client crash dump request callback.
|
||||
// Parameter exit_callback: Callback for client process exit.
|
||||
// Parameter exit_context: Context for client exit callback.
|
||||
// Parameter generate_dumps: Whether to automatically generate dumps.
|
||||
// Client code of this class might want to generate dumps explicitly in the
|
||||
// crash dump request callback. In that case, false can be passed for this
|
||||
// parameter.
|
||||
// Parameter dump_path: Path for generating dumps; required only if true is
|
||||
// passed for generateDumps parameter; NULL can be passed otherwise.
|
||||
CrashGenerationServer(const std::wstring& pipe_name, |
||||
SECURITY_ATTRIBUTES* pipe_sec_attrs, |
||||
OnClientConnectedCallback connect_callback, |
||||
void* connect_context, |
||||
OnClientDumpRequestCallback dump_callback, |
||||
void* dump_context, |
||||
OnClientExitedCallback exit_callback, |
||||
void* exit_context, |
||||
bool generate_dumps, |
||||
const std::wstring* dump_path); |
||||
|
||||
~CrashGenerationServer(); |
||||
|
||||
// Performs initialization steps needed to start listening to clients.
|
||||
//
|
||||
// Returns true if initialization is successful; false otherwise.
|
||||
bool Start(); |
||||
|
||||
private: |
||||
// Various states the client can be in during the handshake with
|
||||
// the server.
|
||||
enum IPCServerState { |
||||
// Server is in error state and it cannot serve any clients.
|
||||
IPC_SERVER_STATE_ERROR, |
||||
|
||||
// Server starts in this state.
|
||||
IPC_SERVER_STATE_INITIAL, |
||||
|
||||
// Server has issued an async connect to the pipe and it is waiting
|
||||
// for the connection to be established.
|
||||
IPC_SERVER_STATE_CONNECTING, |
||||
|
||||
// Server is connected successfully.
|
||||
IPC_SERVER_STATE_CONNECTED, |
||||
|
||||
// Server has issued an async read from the pipe and it is waiting for
|
||||
// the read to finish.
|
||||
IPC_SERVER_STATE_READING, |
||||
|
||||
// Server is done reading from the pipe.
|
||||
IPC_SERVER_STATE_READ_DONE, |
||||
|
||||
// Server has issued an async write to the pipe and it is waiting for
|
||||
// the write to finish.
|
||||
IPC_SERVER_STATE_WRITING, |
||||
|
||||
// Server is done writing to the pipe.
|
||||
IPC_SERVER_STATE_WRITE_DONE, |
||||
|
||||
// Server has issued an async read from the pipe for an ack and it
|
||||
// is waiting for the read to finish.
|
||||
IPC_SERVER_STATE_READING_ACK, |
||||
|
||||
// Server is done writing to the pipe and it is now ready to disconnect
|
||||
// and reconnect.
|
||||
IPC_SERVER_STATE_DISCONNECTING |
||||
}; |
||||
|
||||
//
|
||||
// Helper methods to handle various server IPC states.
|
||||
//
|
||||
void HandleErrorState(); |
||||
void HandleInitialState(); |
||||
void HandleConnectingState(); |
||||
void HandleConnectedState(); |
||||
void HandleReadingState(); |
||||
void HandleReadDoneState(); |
||||
void HandleWritingState(); |
||||
void HandleWriteDoneState(); |
||||
void HandleReadingAckState(); |
||||
void HandleDisconnectingState(); |
||||
|
||||
// Prepares reply for a client from the given parameters.
|
||||
bool PrepareReply(const ClientInfo& client_info, |
||||
ProtocolMessage* reply) const; |
||||
|
||||
// Duplicates various handles in the ClientInfo object for the client
|
||||
// process and stores them in the given ProtocolMessage instance. If
|
||||
// creating any handle fails, ProtocolMessage will contain the handles
|
||||
// already created successfully, which should be closed by the caller.
|
||||
bool CreateClientHandles(const ClientInfo& client_info, |
||||
ProtocolMessage* reply) const; |
||||
|
||||
// Response to the given client. Return true if all steps of
|
||||
// responding to the client succeed, false otherwise.
|
||||
bool RespondToClient(ClientInfo* client_info); |
||||
|
||||
// Handles a connection request from the client.
|
||||
void HandleConnectionRequest(); |
||||
|
||||
// Handles a dump request from the client.
|
||||
void HandleDumpRequest(const ClientInfo& client_info); |
||||
|
||||
// Callback for pipe connected event.
|
||||
static void CALLBACK OnPipeConnected(void* context, BOOLEAN timer_or_wait); |
||||
|
||||
// Callback for a dump request.
|
||||
static void CALLBACK OnDumpRequest(void* context, BOOLEAN timer_or_wait); |
||||
|
||||
// Callback for client process exit event.
|
||||
static void CALLBACK OnClientEnd(void* context, BOOLEAN timer_or_wait); |
||||
|
||||
// Releases resources for a client.
|
||||
static DWORD WINAPI CleanupClient(void* context); |
||||
|
||||
// Cleans up for the given client.
|
||||
void DoCleanup(ClientInfo* client_info); |
||||
|
||||
// Adds the given client to the list of registered clients.
|
||||
bool AddClient(ClientInfo* client_info); |
||||
|
||||
// Generates dump for the given client.
|
||||
bool GenerateDump(const ClientInfo& client, std::wstring* dump_path); |
||||
|
||||
// Sync object for thread-safe access to the shared list of clients.
|
||||
CRITICAL_SECTION clients_sync_; |
||||
|
||||
// List of clients.
|
||||
std::list<ClientInfo*> clients_; |
||||
|
||||
// Pipe name.
|
||||
std::wstring pipe_name_; |
||||
|
||||
// Pipe security attributes
|
||||
SECURITY_ATTRIBUTES* pipe_sec_attrs_; |
||||
|
||||
// Handle to the pipe used for handshake with clients.
|
||||
HANDLE pipe_; |
||||
|
||||
// Pipe wait handle.
|
||||
HANDLE pipe_wait_handle_; |
||||
|
||||
// Handle to server-alive mutex.
|
||||
HANDLE server_alive_handle_; |
||||
|
||||
// Callback for a successful client connection.
|
||||
OnClientConnectedCallback connect_callback_; |
||||
|
||||
// Context for client connected callback.
|
||||
void* connect_context_; |
||||
|
||||
// Callback for a client dump request.
|
||||
OnClientDumpRequestCallback dump_callback_; |
||||
|
||||
// Context for client dump request callback.
|
||||
void* dump_context_; |
||||
|
||||
// Callback for client process exit.
|
||||
OnClientExitedCallback exit_callback_; |
||||
|
||||
// Context for client process exit callback.
|
||||
void* exit_context_; |
||||
|
||||
// Whether to generate dumps.
|
||||
bool generate_dumps_; |
||||
|
||||
// Instance of a mini dump generator.
|
||||
scoped_ptr<MinidumpGenerator> dump_generator_; |
||||
|
||||
// State of the server in performing the IPC with the client.
|
||||
// Note that since we restrict the pipe to one instance, we
|
||||
// only need to keep one state of the server. Otherwise, server
|
||||
// would have one state per client it is talking to.
|
||||
volatile IPCServerState server_state_; |
||||
|
||||
// Whether the server is shutting down.
|
||||
volatile bool shutting_down_; |
||||
|
||||
// Overlapped instance for async I/O on the pipe.
|
||||
OVERLAPPED overlapped_; |
||||
|
||||
// Message object used in IPC with the client.
|
||||
ProtocolMessage msg_; |
||||
|
||||
// Client Info for the client that's connecting to the server.
|
||||
ClientInfo* client_info_; |
||||
|
||||
// Count of clean-up work items that are currently running or are
|
||||
// already queued to run.
|
||||
volatile LONG cleanup_item_count_; |
||||
|
||||
// Disable copy ctor and operator=.
|
||||
CrashGenerationServer(const CrashGenerationServer& crash_server); |
||||
CrashGenerationServer& operator=(const CrashGenerationServer& crash_server); |
||||
}; |
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_SERVER_H__
|
@ -0,0 +1,121 @@ |
||||
// Copyright (c) 2008, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef CLIENT_WINDOWS_CRASH_GENERATION_MINIDUMP_GENERATION_H__ |
||||
#define CLIENT_WINDOWS_CRASH_GENERATION_MINIDUMP_GENERATION_H__ |
||||
|
||||
#include <windows.h> |
||||
#include <dbghelp.h> |
||||
#include <list> |
||||
#include "google_breakpad/common/minidump_format.h" |
||||
|
||||
namespace google_breakpad { |
||||
|
||||
// Abstraction for various objects and operations needed to generate
|
||||
// minidump on Windows. This abstraction is useful to hide all the gory
|
||||
// details for minidump generation and provide a clean interface to
|
||||
// the clients to generate minidumps.
|
||||
class MinidumpGenerator { |
||||
public: |
||||
// Creates an instance with the given dump path.
|
||||
explicit MinidumpGenerator(const std::wstring& dump_path); |
||||
|
||||
~MinidumpGenerator(); |
||||
|
||||
// Writes the minidump with the given parameters. Stores the
|
||||
// dump file path in the dump_path parameter if dump generation
|
||||
// succeeds.
|
||||
bool WriteMinidump(HANDLE process_handle, |
||||
DWORD process_id, |
||||
DWORD thread_id, |
||||
DWORD requesting_thread_id, |
||||
EXCEPTION_POINTERS* exception_pointers, |
||||
MDRawAssertionInfo* assert_info, |
||||
MINIDUMP_TYPE dump_type, |
||||
bool is_client_pointers, |
||||
std::wstring* dump_path); |
||||
|
||||
private: |
||||
// Function pointer type for MiniDumpWriteDump, which is looked up
|
||||
// dynamically.
|
||||
typedef BOOL (WINAPI* MiniDumpWriteDumpType)( |
||||
HANDLE hProcess, |
||||
DWORD ProcessId, |
||||
HANDLE hFile, |
||||
MINIDUMP_TYPE DumpType, |
||||
CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, |
||||
CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, |
||||
CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam); |
||||
|
||||
// Function pointer type for UuidCreate, which is looked up dynamically.
|
||||
typedef RPC_STATUS (RPC_ENTRY* UuidCreateType)(UUID* Uuid); |
||||
|
||||
// Loads the appropriate DLL lazily in a thread safe way.
|
||||
HMODULE GetDbghelpModule(); |
||||
|
||||
// Loads the appropriate DLL and gets a pointer to the MiniDumpWriteDump
|
||||
// function lazily and in a thread-safe manner.
|
||||
MiniDumpWriteDumpType GetWriteDump(); |
||||
|
||||
// Loads the appropriate DLL lazily in a thread safe way.
|
||||
HMODULE GetRpcrt4Module(); |
||||
|
||||
// Loads the appropriate DLL and gets a pointer to the UuidCreate
|
||||
// function lazily and in a thread-safe manner.
|
||||
UuidCreateType GetCreateUuid(); |
||||
|
||||
// Returns the path for the file to write dump to.
|
||||
bool GenerateDumpFilePath(std::wstring* file_path); |
||||
|
||||
// Handle to dynamically loaded DbgHelp.dll.
|
||||
HMODULE dbghelp_module_; |
||||
|
||||
// Pointer to the MiniDumpWriteDump function.
|
||||
MiniDumpWriteDumpType write_dump_; |
||||
|
||||
// Handle to dynamically loaded rpcrt4.dll.
|
||||
HMODULE rpcrt4_module_; |
||||
|
||||
// Pointer to the UuidCreate function.
|
||||
UuidCreateType create_uuid_; |
||||
|
||||
// Folder path to store dump files.
|
||||
std::wstring dump_path_; |
||||
|
||||
// Critical section to sychronize action of loading modules dynamically.
|
||||
CRITICAL_SECTION module_load_sync_; |
||||
|
||||
// Critical section to synchronize action of dynamically getting function
|
||||
// addresses from modules.
|
||||
CRITICAL_SECTION get_proc_address_sync_; |
||||
}; |
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // CLIENT_WINDOWS_CRASH_GENERATION_MINIDUMP_GENERATION_H__
|
@ -0,0 +1,415 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// ExceptionHandler can write a minidump file when an exception occurs,
|
||||
// or when WriteMinidump() is called explicitly by your program.
|
||||
//
|
||||
// To have the exception handler write minidumps when an uncaught exception
|
||||
// (crash) occurs, you should create an instance early in the execution
|
||||
// of your program, and keep it around for the entire time you want to
|
||||
// have crash handling active (typically, until shutdown).
|
||||
//
|
||||
// If you want to write minidumps without installing the exception handler,
|
||||
// you can create an ExceptionHandler with install_handler set to false,
|
||||
// then call WriteMinidump. You can also use this technique if you want to
|
||||
// use different minidump callbacks for different call sites.
|
||||
//
|
||||
// In either case, a callback function is called when a minidump is written,
|
||||
// which receives the unqiue id of the minidump. The caller can use this
|
||||
// id to collect and write additional application state, and to launch an
|
||||
// external crash-reporting application.
|
||||
//
|
||||
// It is important that creation and destruction of ExceptionHandler objects
|
||||
// be nested cleanly, when using install_handler = true.
|
||||
// Avoid the following pattern:
|
||||
// ExceptionHandler *e = new ExceptionHandler(...);
|
||||
// ExceptionHandler *f = new ExceptionHandler(...);
|
||||
// delete e;
|
||||
// This will put the exception filter stack into an inconsistent state.
|
||||
|
||||
#ifndef CLIENT_WINDOWS_HANDLER_EXCEPTION_HANDLER_H__ |
||||
#define CLIENT_WINDOWS_HANDLER_EXCEPTION_HANDLER_H__ |
||||
|
||||
#include <stdlib.h> |
||||
#include <Windows.h> |
||||
#include <DbgHelp.h> |
||||
#include <rpc.h> |
||||
|
||||
#pragma warning( push ) |
||||
// Disable exception handler warnings.
|
||||
#pragma warning( disable : 4530 ) |
||||
|
||||
#include <string> |
||||
#include <vector> |
||||
|
||||
#include "client/windows/common/ipc_protocol.h" |
||||
#include "client/windows/crash_generation/crash_generation_client.h" |
||||
#include "google_breakpad/common/minidump_format.h" |
||||
#include "processor/scoped_ptr.h" |
||||
|
||||
namespace google_breakpad { |
||||
|
||||
using std::vector; |
||||
using std::wstring; |
||||
|
||||
class ExceptionHandler { |
||||
public: |
||||
// A callback function to run before Breakpad performs any substantial
|
||||
// processing of an exception. A FilterCallback is called before writing
|
||||
// a minidump. context is the parameter supplied by the user as
|
||||
// callback_context when the handler was created. exinfo points to the
|
||||
// exception record, if any; assertion points to assertion information,
|
||||
// if any.
|
||||
//
|
||||
// If a FilterCallback returns true, Breakpad will continue processing,
|
||||
// attempting to write a minidump. If a FilterCallback returns false, Breakpad
|
||||
// will immediately report the exception as unhandled without writing a
|
||||
// minidump, allowing another handler the opportunity to handle it.
|
||||
typedef bool (*FilterCallback)(void* context, EXCEPTION_POINTERS* exinfo, |
||||
MDRawAssertionInfo* assertion); |
||||
|
||||
// A callback function to run after the minidump has been written.
|
||||
// minidump_id is a unique id for the dump, so the minidump
|
||||
// file is <dump_path>\<minidump_id>.dmp. context is the parameter supplied
|
||||
// by the user as callback_context when the handler was created. exinfo
|
||||
// points to the exception record, or NULL if no exception occurred.
|
||||
// succeeded indicates whether a minidump file was successfully written.
|
||||
// assertion points to information about an assertion if the handler was
|
||||
// invoked by an assertion.
|
||||
//
|
||||
// If an exception occurred and the callback returns true, Breakpad will treat
|
||||
// the exception as fully-handled, suppressing any other handlers from being
|
||||
// notified of the exception. If the callback returns false, Breakpad will
|
||||
// treat the exception as unhandled, and allow another handler to handle it.
|
||||
// If there are no other handlers, Breakpad will report the exception to the
|
||||
// system as unhandled, allowing a debugger or native crash dialog the
|
||||
// opportunity to handle the exception. Most callback implementations
|
||||
// should normally return the value of |succeeded|, or when they wish to
|
||||
// not report an exception of handled, false. Callbacks will rarely want to
|
||||
// return true directly (unless |succeeded| is true).
|
||||
//
|
||||
// For out-of-process dump generation, dump path and minidump ID will always
|
||||
// be NULL. In case of out-of-process dump generation, the dump path and
|
||||
// minidump id are controlled by the server process and are not communicated
|
||||
// back to the crashing process.
|
||||
typedef bool (*MinidumpCallback)(const wchar_t* dump_path, |
||||
const wchar_t* minidump_id, |
||||
void* context, |
||||
EXCEPTION_POINTERS* exinfo, |
||||
MDRawAssertionInfo* assertion, |
||||
bool succeeded); |
||||
|
||||
// HandlerType specifies which types of handlers should be installed, if
|
||||
// any. Use HANDLER_NONE for an ExceptionHandler that remains idle,
|
||||
// without catching any failures on its own. This type of handler may
|
||||
// still be triggered by calling WriteMinidump. Otherwise, use a
|
||||
// combination of the other HANDLER_ values, or HANDLER_ALL to install
|
||||
// all handlers.
|
||||
enum HandlerType { |
||||
HANDLER_NONE = 0, |
||||
HANDLER_EXCEPTION = 1 << 0, // SetUnhandledExceptionFilter
|
||||
HANDLER_INVALID_PARAMETER = 1 << 1, // _set_invalid_parameter_handler
|
||||
HANDLER_PURECALL = 1 << 2, // _set_purecall_handler
|
||||
HANDLER_ALL = HANDLER_EXCEPTION | |
||||
HANDLER_INVALID_PARAMETER | |
||||
HANDLER_PURECALL |
||||
}; |
||||
|
||||
// Creates a new ExceptionHandler instance to handle writing minidumps.
|
||||
// Before writing a minidump, the optional filter callback will be called.
|
||||
// Its return value determines whether or not Breakpad should write a
|
||||
// minidump. Minidump files will be written to dump_path, and the optional
|
||||
// callback is called after writing the dump file, as described above.
|
||||
// handler_types specifies the types of handlers that should be installed.
|
||||
ExceptionHandler(const wstring& dump_path, |
||||
FilterCallback filter, |
||||
MinidumpCallback callback, |
||||
void* callback_context, |
||||
int handler_types); |
||||
|
||||
// Creates a new ExcetpionHandler instance that can attempt to perform
|
||||
// out-of-process dump generation if pipe_name is not NULL. If pipe_name is
|
||||
// NULL, or if out-of-process dump generation registration step fails,
|
||||
// in-process dump generation will be used. This also allows specifying
|
||||
// the dump type to generate.
|
||||
ExceptionHandler(const wstring& dump_path, |
||||
FilterCallback filter, |
||||
MinidumpCallback callback, |
||||
void* callback_context, |
||||
int handler_types, |
||||
MINIDUMP_TYPE dump_type, |
||||
const wchar_t* pipe_name, |
||||
const CustomClientInfo* custom_info); |
||||
|
||||
~ExceptionHandler(); |
||||
|
||||
// Get and set the minidump path.
|
||||
wstring dump_path() const { return dump_path_; } |
||||
void set_dump_path(const wstring &dump_path) { |
||||
dump_path_ = dump_path; |
||||
dump_path_c_ = dump_path_.c_str(); |
||||
UpdateNextID(); // Necessary to put dump_path_ in next_minidump_path_.
|
||||
} |
||||
|
||||
// Writes a minidump immediately. This can be used to capture the
|
||||
// execution state independently of a crash. Returns true on success.
|
||||
bool WriteMinidump(); |
||||
|
||||
// Writes a minidump immediately, with the user-supplied exception
|
||||
// information.
|
||||
bool WriteMinidumpForException(EXCEPTION_POINTERS* exinfo); |
||||
|
||||
// Convenience form of WriteMinidump which does not require an
|
||||
// ExceptionHandler instance.
|
||||
static bool WriteMinidump(const wstring &dump_path, |
||||
MinidumpCallback callback, void* callback_context); |
||||
|
||||
// Get the thread ID of the thread requesting the dump (either the exception
|
||||
// thread or any other thread that called WriteMinidump directly). This
|
||||
// may be useful if you want to include additional thread state in your
|
||||
// dumps.
|
||||
DWORD get_requesting_thread_id() const { return requesting_thread_id_; } |
||||
|
||||
// Controls behavior of EXCEPTION_BREAKPOINT and EXCEPTION_SINGLE_STEP.
|
||||
bool get_handle_debug_exceptions() const { return handle_debug_exceptions_; } |
||||
void set_handle_debug_exceptions(bool handle_debug_exceptions) { |
||||
handle_debug_exceptions_ = handle_debug_exceptions; |
||||
} |
||||
|
||||
// Returns whether out-of-process dump generation is used or not.
|
||||
bool IsOutOfProcess() const { return crash_generation_client_.get() != NULL; } |
||||
|
||||
private: |
||||
friend class AutoExceptionHandler; |
||||
|
||||
// Initializes the instance with given values.
|
||||
void Initialize(const wstring& dump_path, |
||||
FilterCallback filter, |
||||
MinidumpCallback callback, |
||||
void* callback_context, |
||||
int handler_types, |
||||
MINIDUMP_TYPE dump_type, |
||||
const wchar_t* pipe_name, |
||||
const CustomClientInfo* custom_info); |
||||
|
||||
// Function pointer type for MiniDumpWriteDump, which is looked up
|
||||
// dynamically.
|
||||
typedef BOOL (WINAPI *MiniDumpWriteDump_type)( |
||||
HANDLE hProcess, |
||||
DWORD dwPid, |
||||
HANDLE hFile, |
||||
MINIDUMP_TYPE DumpType, |
||||
CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, |
||||
CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, |
||||
CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam); |
||||
|
||||
// Function pointer type for UuidCreate, which is looked up dynamically.
|
||||
typedef RPC_STATUS (RPC_ENTRY *UuidCreate_type)(UUID* Uuid); |
||||
|
||||
// Runs the main loop for the exception handler thread.
|
||||
static DWORD WINAPI ExceptionHandlerThreadMain(void* lpParameter); |
||||
|
||||
// Called on the exception thread when an unhandled exception occurs.
|
||||
// Signals the exception handler thread to handle the exception.
|
||||
static LONG WINAPI HandleException(EXCEPTION_POINTERS* exinfo); |
||||
|
||||
#if _MSC_VER >= 1400 // MSVC 2005/8
|
||||
// This function will be called by some CRT functions when they detect
|
||||
// that they were passed an invalid parameter. Note that in _DEBUG builds,
|
||||
// the CRT may display an assertion dialog before calling this function,
|
||||
// and the function will not be called unless the assertion dialog is
|
||||
// dismissed by clicking "Ignore."
|
||||
static void HandleInvalidParameter(const wchar_t* expression, |
||||
const wchar_t* function, |
||||
const wchar_t* file, |
||||
unsigned int line, |
||||
uintptr_t reserved); |
||||
#endif // _MSC_VER >= 1400
|
||||
|
||||
// This function will be called by the CRT when a pure virtual
|
||||
// function is called.
|
||||
static void HandlePureVirtualCall(); |
||||
|
||||
// This is called on the exception thread or on another thread that
|
||||
// the user wishes to produce a dump from. It calls
|
||||
// WriteMinidumpWithException on the handler thread, avoiding stack
|
||||
// overflows and inconsistent dumps due to writing the dump from
|
||||
// the exception thread. If the dump is requested as a result of an
|
||||
// exception, exinfo contains exception information, otherwise, it
|
||||
// is NULL. If the dump is requested as a result of an assertion
|
||||
// (such as an invalid parameter being passed to a CRT function),
|
||||
// assertion contains data about the assertion, otherwise, it is NULL.
|
||||
bool WriteMinidumpOnHandlerThread(EXCEPTION_POINTERS* exinfo, |
||||
MDRawAssertionInfo* assertion); |
||||
|
||||
// This function does the actual writing of a minidump. It is called
|
||||
// on the handler thread. requesting_thread_id is the ID of the thread
|
||||
// that requested the dump. If the dump is requested as a result of
|
||||
// an exception, exinfo contains exception information, otherwise,
|
||||
// it is NULL.
|
||||
bool WriteMinidumpWithException(DWORD requesting_thread_id, |
||||
EXCEPTION_POINTERS* exinfo, |
||||
MDRawAssertionInfo* assertion); |
||||
|
||||
// Generates a new ID and stores it in next_minidump_id_, and stores the
|
||||
// path of the next minidump to be written in next_minidump_path_.
|
||||
void UpdateNextID(); |
||||
|
||||
FilterCallback filter_; |
||||
MinidumpCallback callback_; |
||||
void* callback_context_; |
||||
|
||||
scoped_ptr<CrashGenerationClient> crash_generation_client_; |
||||
|
||||
// The directory in which a minidump will be written, set by the dump_path
|
||||
// argument to the constructor, or set_dump_path.
|
||||
wstring dump_path_; |
||||
|
||||
// The basename of the next minidump to be written, without the extension.
|
||||
wstring next_minidump_id_; |
||||
|
||||
// The full pathname of the next minidump to be written, including the file
|
||||
// extension.
|
||||
wstring next_minidump_path_; |
||||
|
||||
// Pointers to C-string representations of the above. These are set when
|
||||
// the above wstring versions are set in order to avoid calling c_str during
|
||||
// an exception, as c_str may attempt to allocate heap memory. These
|
||||
// pointers are not owned by the ExceptionHandler object, but their lifetimes
|
||||
// should be equivalent to the lifetimes of the associated wstring, provided
|
||||
// that the wstrings are not altered.
|
||||
const wchar_t* dump_path_c_; |
||||
const wchar_t* next_minidump_id_c_; |
||||
const wchar_t* next_minidump_path_c_; |
||||
|
||||
HMODULE dbghelp_module_; |
||||
MiniDumpWriteDump_type minidump_write_dump_; |
||||
MINIDUMP_TYPE dump_type_; |
||||
|
||||
HMODULE rpcrt4_module_; |
||||
UuidCreate_type uuid_create_; |
||||
|
||||
// Tracks the handler types that were installed according to the
|
||||
// handler_types constructor argument.
|
||||
int handler_types_; |
||||
|
||||
// When installed_handler_ is true, previous_filter_ is the unhandled
|
||||
// exception filter that was set prior to installing ExceptionHandler as
|
||||
// the unhandled exception filter and pointing it to |this|. NULL indicates
|
||||
// that there is no previous unhandled exception filter.
|
||||
LPTOP_LEVEL_EXCEPTION_FILTER previous_filter_; |
||||
|
||||
#if _MSC_VER >= 1400 // MSVC 2005/8
|
||||
// Beginning in VC 8, the CRT provides an invalid parameter handler that will
|
||||
// be called when some CRT functions are passed invalid parameters. In
|
||||
// earlier CRTs, the same conditions would cause unexpected behavior or
|
||||
// crashes.
|
||||
_invalid_parameter_handler previous_iph_; |
||||
#endif // _MSC_VER >= 1400
|
||||
|
||||
// The CRT allows you to override the default handler for pure
|
||||
// virtual function calls.
|
||||
_purecall_handler previous_pch_; |
||||
|
||||
// The exception handler thread.
|
||||
HANDLE handler_thread_; |
||||
|
||||
// True if the exception handler is being destroyed.
|
||||
// Starting with MSVC 2005, Visual C has stronger guarantees on volatile vars.
|
||||
// It has release semantics on write and acquire semantics on reads.
|
||||
// See the msdn documentation.
|
||||
volatile bool is_shutdown_; |
||||
|
||||
// The critical section enforcing the requirement that only one exception be
|
||||
// handled by a handler at a time.
|
||||
CRITICAL_SECTION handler_critical_section_; |
||||
|
||||
// Semaphores used to move exception handling between the exception thread
|
||||
// and the handler thread. handler_start_semaphore_ is signalled by the
|
||||
// exception thread to wake up the handler thread when an exception occurs.
|
||||
// handler_finish_semaphore_ is signalled by the handler thread to wake up
|
||||
// the exception thread when handling is complete.
|
||||
HANDLE handler_start_semaphore_; |
||||
HANDLE handler_finish_semaphore_; |
||||
|
||||
// The next 2 fields contain data passed from the requesting thread to
|
||||
// the handler thread.
|
||||
|
||||
// The thread ID of the thread requesting the dump (either the exception
|
||||
// thread or any other thread that called WriteMinidump directly).
|
||||
DWORD requesting_thread_id_; |
||||
|
||||
// The exception info passed to the exception handler on the exception
|
||||
// thread, if an exception occurred. NULL for user-requested dumps.
|
||||
EXCEPTION_POINTERS* exception_info_; |
||||
|
||||
// If the handler is invoked due to an assertion, this will contain a
|
||||
// pointer to the assertion information. It is NULL at other times.
|
||||
MDRawAssertionInfo* assertion_; |
||||
|
||||
// The return value of the handler, passed from the handler thread back to
|
||||
// the requesting thread.
|
||||
bool handler_return_value_; |
||||
|
||||
// If true, the handler will intercept EXCEPTION_BREAKPOINT and
|
||||
// EXCEPTION_SINGLE_STEP exceptions. Leave this false (the default)
|
||||
// to not interfere with debuggers.
|
||||
bool handle_debug_exceptions_; |
||||
|
||||
// A stack of ExceptionHandler objects that have installed unhandled
|
||||
// exception filters. This vector is used by HandleException to determine
|
||||
// which ExceptionHandler object to route an exception to. When an
|
||||
// ExceptionHandler is created with install_handler true, it will append
|
||||
// itself to this list.
|
||||
static vector<ExceptionHandler*>* handler_stack_; |
||||
|
||||
// The index of the ExceptionHandler in handler_stack_ that will handle the
|
||||
// next exception. Note that 0 means the last entry in handler_stack_, 1
|
||||
// means the next-to-last entry, and so on. This is used by HandleException
|
||||
// to support multiple stacked Breakpad handlers.
|
||||
static LONG handler_stack_index_; |
||||
|
||||
// handler_stack_critical_section_ guards operations on handler_stack_ and
|
||||
// handler_stack_index_. The critical section is initialized by the
|
||||
// first instance of the class and destroyed by the last instance of it.
|
||||
static CRITICAL_SECTION handler_stack_critical_section_; |
||||
|
||||
// The number of instances of this class.
|
||||
volatile static LONG instance_count_; |
||||
|
||||
// disallow copy ctor and operator=
|
||||
explicit ExceptionHandler(const ExceptionHandler &); |
||||
void operator=(const ExceptionHandler &); |
||||
}; |
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#pragma warning( pop ) |
||||
|
||||
#endif // CLIENT_WINDOWS_HANDLER_EXCEPTION_HANDLER_H__
|
@ -0,0 +1,125 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef CLIENT_WINDOWS_SENDER_CRASH_REPORT_SENDER_H__ |
||||
#define CLIENT_WINDOWS_SENDER_CRASH_REPORT_SENDER_H__ |
||||
|
||||
// CrashReportSender is a "static" class which provides an API to upload
|
||||
// crash reports via HTTP(S). A crash report is formatted as a multipart POST
|
||||
// request, which contains a set of caller-supplied string key/value pairs,
|
||||
// and a minidump file to upload.
|
||||
//
|
||||
// To use this library in your project, you will need to link against
|
||||
// wininet.lib.
|
||||
|
||||
#pragma warning( push ) |
||||
// Disable exception handler warnings.
|
||||
#pragma warning( disable : 4530 ) |
||||
|
||||
#include <map> |
||||
#include <string> |
||||
|
||||
namespace google_breakpad { |
||||
|
||||
using std::wstring; |
||||
using std::map; |
||||
|
||||
typedef enum { |
||||
RESULT_FAILED = 0, // Failed to communicate with the server; try later.
|
||||
RESULT_REJECTED, // Successfully sent the crash report, but the
|
||||
// server rejected it; don't resend this report.
|
||||
RESULT_SUCCEEDED, // The server accepted the crash report.
|
||||
RESULT_THROTTLED // No attempt was made to send the crash report, because
|
||||
// we exceeded the maximum reports per day.
|
||||
} ReportResult; |
||||
|
||||
class CrashReportSender { |
||||
public: |
||||
// Initializes a CrashReportSender instance.
|
||||
// If checkpoint_file is non-empty, breakpad will persist crash report
|
||||
// state to this file. A checkpoint file is required for
|
||||
// set_max_reports_per_day() to function properly.
|
||||
explicit CrashReportSender(const wstring &checkpoint_file); |
||||
~CrashReportSender() {} |
||||
|
||||
// Sets the maximum number of crash reports that will be sent in a 24-hour
|
||||
// period. This uses the state persisted to the checkpoint file.
|
||||
// The default value of -1 means that there is no limit on reports sent.
|
||||
void set_max_reports_per_day(int reports) { |
||||
max_reports_per_day_ = reports; |
||||
} |
||||
|
||||
int max_reports_per_day() const { return max_reports_per_day_; } |
||||
|
||||
// Sends the specified minidump file, along with the map of
|
||||
// name value pairs, as a multipart POST request to the given URL.
|
||||
// Parameter names must contain only printable ASCII characters,
|
||||
// and may not contain a quote (") character.
|
||||
// Only HTTP(S) URLs are currently supported. The return value indicates
|
||||
// the result of the operation (see above for possible results).
|
||||
// If report_code is non-NULL and the report is sent successfully (that is,
|
||||
// the return value is RESULT_SUCCEEDED), a code uniquely identifying the
|
||||
// report will be returned in report_code.
|
||||
// (Otherwise, report_code will be unchanged.)
|
||||
ReportResult SendCrashReport(const wstring &url, |
||||
const map<wstring, wstring> ¶meters, |
||||
const wstring &dump_file_name, |
||||
wstring *report_code); |
||||
|
||||
private: |
||||
// Reads persistent state from a checkpoint file.
|
||||
void ReadCheckpoint(FILE *fd); |
||||
|
||||
// Called when a new report has been sent, to update the checkpoint state.
|
||||
void ReportSent(int today); |
||||
|
||||
// Returns today's date (UTC) formatted as YYYYMMDD.
|
||||
int GetCurrentDate() const; |
||||
|
||||
// Opens the checkpoint file with the specified mode.
|
||||
// Returns zero on success, or an error code on failure.
|
||||
int OpenCheckpointFile(const wchar_t *mode, FILE **fd); |
||||
|
||||
wstring checkpoint_file_; |
||||
int max_reports_per_day_; |
||||
// The last date on which we sent a report, expressed as YYYYMMDD.
|
||||
int last_sent_date_; |
||||
// Number of reports sent on last_sent_date_
|
||||
int reports_sent_; |
||||
|
||||
// Disallow copy constructor and operator=
|
||||
explicit CrashReportSender(const CrashReportSender &); |
||||
void operator=(const CrashReportSender &); |
||||
}; |
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#pragma warning( pop ) |
||||
|
||||
#endif // CLIENT_WINDOWS_SENDER_CRASH_REPORT_SENDER_H__
|
@ -0,0 +1,143 @@ |
||||
/*
|
||||
* Copyright 2001-2004 Unicode, Inc. |
||||
* |
||||
* Disclaimer |
||||
* |
||||
* This source code is provided as is by Unicode, Inc. No claims are |
||||
* made as to fitness for any particular purpose. No warranties of any |
||||
* kind are expressed or implied. The recipient agrees to determine |
||||
* applicability of information provided. If this file has been |
||||
* purchased on magnetic or optical media from Unicode, Inc., the |
||||
* sole remedy for any claim will be exchange of defective media |
||||
* within 90 days of receipt. |
||||
* |
||||
* Limitations on Rights to Redistribute This Code |
||||
* |
||||
* Unicode, Inc. hereby grants the right to freely use the information |
||||
* supplied in this file in the creation of products supporting the |
||||
* Unicode Standard, and to make copies of this file in any form |
||||
* for internal or external distribution as long as this notice |
||||
* remains attached. |
||||
*/ |
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
|
||||
Conversions between UTF32, UTF-16, and UTF-8. Header file. |
||||
|
||||
Several funtions are included here, forming a complete set of |
||||
conversions between the three formats. UTF-7 is not included |
||||
here, but is handled in a separate source file. |
||||
|
||||
Each of these routines takes pointers to input buffers and output |
||||
buffers. The input buffers are const. |
||||
|
||||
Each routine converts the text between *sourceStart and sourceEnd, |
||||
putting the result into the buffer between *targetStart and |
||||
targetEnd. Note: the end pointers are *after* the last item: e.g. |
||||
*(sourceEnd - 1) is the last item. |
||||
|
||||
The return result indicates whether the conversion was successful, |
||||
and if not, whether the problem was in the source or target buffers. |
||||
(Only the first encountered problem is indicated.) |
||||
|
||||
After the conversion, *sourceStart and *targetStart are both |
||||
updated to point to the end of last text successfully converted in |
||||
the respective buffers. |
||||
|
||||
Input parameters: |
||||
sourceStart - pointer to a pointer to the source buffer. |
||||
The contents of this are modified on return so that |
||||
it points at the next thing to be converted. |
||||
targetStart - similarly, pointer to pointer to the target buffer. |
||||
sourceEnd, targetEnd - respectively pointers to the ends of the |
||||
two buffers, for overflow checking only. |
||||
|
||||
These conversion functions take a ConversionFlags argument. When this |
||||
flag is set to strict, both irregular sequences and isolated surrogates |
||||
will cause an error. When the flag is set to lenient, both irregular |
||||
sequences and isolated surrogates are converted. |
||||
|
||||
Whether the flag is strict or lenient, all illegal sequences will cause |
||||
an error return. This includes sequences such as: <F4 90 80 80>, <C0 80>, |
||||
or <A0> in UTF-8, and values above 0x10FFFF in UTF-32. Conformant code |
||||
must check for illegal sequences. |
||||
|
||||
When the flag is set to lenient, characters over 0x10FFFF are converted |
||||
to the replacement character; otherwise (when the flag is set to strict) |
||||
they constitute an error. |
||||
|
||||
Output parameters: |
||||
The value "sourceIllegal" is returned from some routines if the input |
||||
sequence is malformed. When "sourceIllegal" is returned, the source |
||||
value will point to the illegal value that caused the problem. E.g., |
||||
in UTF-8 when a sequence is malformed, it points to the start of the |
||||
malformed sequence. |
||||
|
||||
Author: Mark E. Davis, 1994. |
||||
Rev History: Rick McGowan, fixes & updates May 2001. |
||||
Fixes & updates, Sept 2001. |
||||
|
||||
------------------------------------------------------------------------ */ |
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
The following 4 definitions are compiler-specific. |
||||
The C standard does not guarantee that wchar_t has at least |
||||
16 bits, so wchar_t is no less portable than unsigned short! |
||||
All should be unsigned values to avoid sign extension during |
||||
bit mask & shift operations. |
||||
------------------------------------------------------------------------ */ |
||||
|
||||
typedef unsigned long UTF32; /* at least 32 bits */ |
||||
typedef unsigned short UTF16; /* at least 16 bits */ |
||||
typedef unsigned char UTF8; /* typically 8 bits */ |
||||
typedef unsigned char Boolean; /* 0 or 1 */ |
||||
|
||||
/* Some fundamental constants */ |
||||
#define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD |
||||
#define UNI_MAX_BMP (UTF32)0x0000FFFF |
||||
#define UNI_MAX_UTF16 (UTF32)0x0010FFFF |
||||
#define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF |
||||
#define UNI_MAX_LEGAL_UTF32 (UTF32)0x0010FFFF |
||||
|
||||
typedef enum { |
||||
conversionOK, /* conversion successful */ |
||||
sourceExhausted, /* partial character in source, but hit end */ |
||||
targetExhausted, /* insuff. room in target for conversion */ |
||||
sourceIllegal /* source sequence is illegal/malformed */ |
||||
} ConversionResult; |
||||
|
||||
typedef enum { |
||||
strictConversion = 0, |
||||
lenientConversion |
||||
} ConversionFlags; |
||||
|
||||
/* This is for C++ and does no harm in C */ |
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
ConversionResult ConvertUTF8toUTF16 (const UTF8** sourceStart, const UTF8* sourceEnd, |
||||
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags); |
||||
|
||||
ConversionResult ConvertUTF16toUTF8 (const UTF16** sourceStart, const UTF16* sourceEnd, |
||||
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags); |
||||
|
||||
ConversionResult ConvertUTF8toUTF32 (const UTF8** sourceStart, const UTF8* sourceEnd, |
||||
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags); |
||||
|
||||
ConversionResult ConvertUTF32toUTF8 (const UTF32** sourceStart, const UTF32* sourceEnd, |
||||
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags); |
||||
|
||||
ConversionResult ConvertUTF16toUTF32 (const UTF16** sourceStart, const UTF16* sourceEnd, |
||||
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags); |
||||
|
||||
ConversionResult ConvertUTF32toUTF16 (const UTF32** sourceStart, const UTF32* sourceEnd, |
||||
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags); |
||||
|
||||
Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd); |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
/* --------------------------------------------------------------------- */ |
@ -0,0 +1,31 @@ |
||||
// Copyright 2007 Google Inc. All Rights Reserved.
|
||||
// Author: liuli@google.com (Liu Li)
|
||||
#ifndef COMMON_MD5_H__ |
||||
#define COMMON_MD5_H__ |
||||
|
||||
#include <stdint.h> |
||||
|
||||
typedef uint32_t u32; |
||||
typedef uint8_t u8; |
||||
|
||||
struct MD5Context { |
||||
u32 buf[4]; |
||||
u32 bits[2]; |
||||
u8 in[64]; |
||||
}; |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif // __cplusplus
|
||||
|
||||
void MD5Init(struct MD5Context *ctx); |
||||
|
||||
void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len); |
||||
|
||||
void MD5Final(unsigned char digest[16], struct MD5Context *ctx); |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif // COMMON_MD5_H__
|
@ -0,0 +1,66 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// string_conversion.h: Conversion between different UTF-8/16/32 encodings.
|
||||
|
||||
#ifndef COMMON_STRING_CONVERSION_H__ |
||||
#define COMMON_STRING_CONVERSION_H__ |
||||
|
||||
#include <string> |
||||
#include <vector> |
||||
#include "google_breakpad/common/breakpad_types.h" |
||||
|
||||
namespace google_breakpad { |
||||
|
||||
using std::vector; |
||||
|
||||
// Convert |in| to UTF-16 into |out|. Use platform byte ordering. If the
|
||||
// conversion failed, |out| will be zero length.
|
||||
void UTF8ToUTF16(const char *in, vector<u_int16_t> *out); |
||||
|
||||
// Convert at least one character (up to a maximum of |in_length|) from |in|
|
||||
// to UTF-16 into |out|. Return the number of characters consumed from |in|.
|
||||
// Any unused characters in |out| will be initialized to 0. No memory will
|
||||
// be allocated by this routine.
|
||||
int UTF8ToUTF16Char(const char *in, int in_length, u_int16_t out[2]); |
||||
|
||||
// Convert |in| to UTF-16 into |out|. Use platform byte ordering. If the
|
||||
// conversion failed, |out| will be zero length.
|
||||
void UTF32ToUTF16(const wchar_t *in, vector<u_int16_t> *out); |
||||
|
||||
// Convert |in| to UTF-16 into |out|. Any unused characters in |out| will be
|
||||
// initialized to 0. No memory will be allocated by this routine.
|
||||
void UTF32ToUTF16Char(wchar_t in, u_int16_t out[2]); |
||||
|
||||
// Convert |in| to UTF-8. If |swap| is true, swap bytes before converting.
|
||||
std::string UTF16ToUTF8(const vector<u_int16_t> &in, bool swap); |
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // COMMON_STRING_CONVERSION_H__
|
@ -0,0 +1,58 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// guid_string.cc: Convert GUIDs to strings.
|
||||
|
||||
#ifndef COMMON_WINDOWS_GUID_STRING_H__ |
||||
#define COMMON_WINDOWS_GUID_STRING_H__ |
||||
|
||||
#include <Guiddef.h> |
||||
|
||||
#include <string> |
||||
|
||||
namespace google_breakpad { |
||||
|
||||
using std::wstring; |
||||
|
||||
class GUIDString { |
||||
public: |
||||
// Converts guid to a string in the format recommended by RFC 4122 and
|
||||
// returns the string.
|
||||
static wstring GUIDToWString(GUID *guid); |
||||
|
||||
// Converts guid to a string formatted as uppercase hexadecimal, with
|
||||
// no separators, and returns the string. This is the format used for
|
||||
// symbol server identifiers, although identifiers have an age tacked
|
||||
// on to the string.
|
||||
static wstring GUIDToSymbolServerWString(GUID *guid); |
||||
}; |
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // COMMON_WINDOWS_GUID_STRING_H__
|
@ -0,0 +1,125 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// HTTPUpload provides a "nice" API to send a multipart HTTP(S) POST
|
||||
// request using wininet. It currently supports requests that contain
|
||||
// a set of string parameters (key/value pairs), and a file to upload.
|
||||
|
||||
#ifndef COMMON_WINDOWS_HTTP_UPLOAD_H__ |
||||
#define COMMON_WINDOWS_HTTP_UPLOAD_H__ |
||||
|
||||
#pragma warning( push ) |
||||
// Disable exception handler warnings.
|
||||
#pragma warning( disable : 4530 ) |
||||
|
||||
#include <Windows.h> |
||||
#include <WinInet.h> |
||||
|
||||
#include <map> |
||||
#include <string> |
||||
#include <vector> |
||||
|
||||
namespace google_breakpad { |
||||
|
||||
using std::string; |
||||
using std::wstring; |
||||
using std::map; |
||||
using std::vector; |
||||
|
||||
class HTTPUpload { |
||||
public: |
||||
// Sends the given set of parameters, along with the contents of
|
||||
// upload_file, as a multipart POST request to the given URL.
|
||||
// file_part_name contains the name of the file part of the request
|
||||
// (i.e. it corresponds to the name= attribute on an <input type="file">.
|
||||
// Parameter names must contain only printable ASCII characters,
|
||||
// and may not contain a quote (") character.
|
||||
// Only HTTP(S) URLs are currently supported. Returns true on success.
|
||||
// If the request is successful and response_body is non-NULL,
|
||||
// the response body will be returned in response_body.
|
||||
// If response_code is non-NULL, it will be set to the HTTP response code
|
||||
// received (or 0 if the request failed before getting an HTTP response).
|
||||
static bool SendRequest(const wstring &url, |
||||
const map<wstring, wstring> ¶meters, |
||||
const wstring &upload_file, |
||||
const wstring &file_part_name, |
||||
wstring *response_body, |
||||
int *response_code); |
||||
|
||||
private: |
||||
class AutoInternetHandle; |
||||
|
||||
// Retrieves the HTTP response. If NULL is passed in for response,
|
||||
// this merely checks (via the return value) that we were successfully
|
||||
// able to retrieve exactly as many bytes of content in the response as
|
||||
// were specified in the Content-Length header.
|
||||
static bool HTTPUpload::ReadResponse(HINTERNET request, wstring* response); |
||||
|
||||
// Generates a new multipart boundary for a POST request
|
||||
static wstring GenerateMultipartBoundary(); |
||||
|
||||
// Generates a HTTP request header for a multipart form submit.
|
||||
static wstring GenerateRequestHeader(const wstring &boundary); |
||||
|
||||
// Given a set of parameters, an upload filename, and a file part name,
|
||||
// generates a multipart request body string with these parameters
|
||||
// and minidump contents. Returns true on success.
|
||||
static bool GenerateRequestBody(const map<wstring, wstring> ¶meters, |
||||
const wstring &upload_file, |
||||
const wstring &file_part_name, |
||||
const wstring &boundary, |
||||
string *request_body); |
||||
|
||||
// Fills the supplied vector with the contents of filename.
|
||||
static void GetFileContents(const wstring &filename, vector<char> *contents); |
||||
|
||||
// Converts a UTF8 string to UTF16.
|
||||
static wstring UTF8ToWide(const string &utf8); |
||||
|
||||
// Converts a UTF16 string to UTF8.
|
||||
static string WideToUTF8(const wstring &wide); |
||||
|
||||
// Checks that the given list of parameters has only printable
|
||||
// ASCII characters in the parameter name, and does not contain
|
||||
// any quote (") characters. Returns true if so.
|
||||
static bool CheckParameters(const map<wstring, wstring> ¶meters); |
||||
|
||||
// No instances of this class should be created.
|
||||
// Disallow all constructors, destructors, and operator=.
|
||||
HTTPUpload(); |
||||
explicit HTTPUpload(const HTTPUpload &); |
||||
void operator=(const HTTPUpload &); |
||||
~HTTPUpload(); |
||||
}; |
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#pragma warning( pop ) |
||||
|
||||
#endif // COMMON_WINDOWS_HTTP_UPLOAD_H__
|
@ -0,0 +1,163 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// PDBSourceLineWriter uses a pdb file produced by Visual C++ to output
|
||||
// a line/address map for use with BasicSourceLineResolver.
|
||||
|
||||
#ifndef _PDB_SOURCE_LINE_WRITER_H__ |
||||
#define _PDB_SOURCE_LINE_WRITER_H__ |
||||
|
||||
#include <atlcomcli.h> |
||||
|
||||
#include <string> |
||||
|
||||
struct IDiaEnumLineNumbers; |
||||
struct IDiaSession; |
||||
struct IDiaSymbol; |
||||
|
||||
namespace google_breakpad { |
||||
|
||||
using std::wstring; |
||||
|
||||
// A structure that carries information that identifies a pdb file.
|
||||
struct PDBModuleInfo { |
||||
public: |
||||
// The basename of the pdb file from which information was loaded.
|
||||
wstring debug_file; |
||||
|
||||
// The pdb's identifier. For recent pdb files, the identifier consists
|
||||
// of the pdb's guid, in uppercase hexadecimal form without any dashes
|
||||
// or separators, followed immediately by the pdb's age, also in
|
||||
// uppercase hexadecimal form. For older pdb files which have no guid,
|
||||
// the identifier is the pdb's 32-bit signature value, in zero-padded
|
||||
// hexadecimal form, followed immediately by the pdb's age, in lowercase
|
||||
// hexadecimal form.
|
||||
wstring debug_identifier; |
||||
|
||||
// A string identifying the cpu that the pdb is associated with.
|
||||
// Currently, this may be "x86" or "unknown".
|
||||
wstring cpu; |
||||
}; |
||||
|
||||
class PDBSourceLineWriter { |
||||
public: |
||||
enum FileFormat { |
||||
PDB_FILE, // a .pdb file containing debug symbols
|
||||
EXE_FILE, // a .exe or .dll file
|
||||
ANY_FILE // try PDB_FILE and then EXE_FILE
|
||||
}; |
||||
|
||||
explicit PDBSourceLineWriter(); |
||||
~PDBSourceLineWriter(); |
||||
|
||||
// Opens the given file. For executable files, the corresponding pdb
|
||||
// file must be available; Open will be if it is not.
|
||||
// If there is already a pdb file open, it is automatically closed.
|
||||
// Returns true on success.
|
||||
bool Open(const wstring &file, FileFormat format); |
||||
|
||||
// Locates the pdb file for the given executable (exe or dll) file,
|
||||
// and opens it. If there is already a pdb file open, it is automatically
|
||||
// closed. Returns true on success.
|
||||
bool OpenExecutable(const wstring &exe_file); |
||||
|
||||
// Writes a map file from the current pdb file to the given file stream.
|
||||
// Returns true on success.
|
||||
bool WriteMap(FILE *map_file); |
||||
|
||||
// Closes the current pdb file and its associated resources.
|
||||
void Close(); |
||||
|
||||
// Retrieves information about the module's debugging file. Returns
|
||||
// true on success and false on failure.
|
||||
bool GetModuleInfo(PDBModuleInfo *info); |
||||
|
||||
// Sets uses_guid to true if the opened file uses a new-style CodeView
|
||||
// record with a 128-bit GUID, or false if the opened file uses an old-style
|
||||
// CodeView record. When no GUID is available, a 32-bit signature should be
|
||||
// used to identify the module instead. If the information cannot be
|
||||
// determined, this method returns false.
|
||||
bool UsesGUID(bool *uses_guid); |
||||
|
||||
private: |
||||
// Outputs the line/address pairs for each line in the enumerator.
|
||||
// Returns true on success.
|
||||
bool PrintLines(IDiaEnumLineNumbers *lines); |
||||
|
||||
// Outputs a function address and name, followed by its source line list.
|
||||
// Returns true on success.
|
||||
bool PrintFunction(IDiaSymbol *function); |
||||
|
||||
// Outputs all functions as described above. Returns true on success.
|
||||
bool PrintFunctions(); |
||||
|
||||
// Outputs all of the source files in the session's pdb file.
|
||||
// Returns true on success.
|
||||
bool PrintSourceFiles(); |
||||
|
||||
// Outputs all of the frame information necessary to construct stack
|
||||
// backtraces in the absence of frame pointers. Returns true on success.
|
||||
bool PrintFrameData(); |
||||
|
||||
// Outputs a single public symbol address and name, if the symbol corresponds
|
||||
// to a code address. Returns true on success. If symbol is does not
|
||||
// correspond to code, returns true without outputting anything.
|
||||
bool PrintCodePublicSymbol(IDiaSymbol *symbol); |
||||
|
||||
// Outputs a line identifying the PDB file that is being dumped, along with
|
||||
// its uuid and age.
|
||||
bool PrintPDBInfo(); |
||||
|
||||
// Returns the function name for a symbol. If possible, the name is
|
||||
// undecorated. If the symbol's decorated form indicates the size of
|
||||
// parameters on the stack, this information is returned in stack_param_size.
|
||||
// Returns true on success. If the symbol doesn't encode parameter size
|
||||
// information, stack_param_size is set to -1.
|
||||
static bool GetSymbolFunctionName(IDiaSymbol *function, BSTR *name, |
||||
int *stack_param_size); |
||||
|
||||
// Returns the number of bytes of stack space used for a function's
|
||||
// parameters. function must have the tag SymTagFunction. In the event of
|
||||
// a failure, returns 0, which is also a valid number of bytes.
|
||||
static int GetFunctionStackParamSize(IDiaSymbol *function); |
||||
|
||||
// The session for the currently-open pdb file.
|
||||
CComPtr<IDiaSession> session_; |
||||
|
||||
// The current output file for this WriteMap invocation.
|
||||
FILE *output_; |
||||
|
||||
// Disallow copy ctor and operator=
|
||||
PDBSourceLineWriter(const PDBSourceLineWriter&); |
||||
void operator=(const PDBSourceLineWriter&); |
||||
}; |
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // _PDB_SOURCE_LINE_WRITER_H__
|
@ -0,0 +1,139 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// string_utils-inl.h: Safer string manipulation on Windows, supporting
|
||||
// pre-MSVC8 environments.
|
||||
|
||||
#ifndef COMMON_WINDOWS_STRING_UTILS_INL_H__ |
||||
#define COMMON_WINDOWS_STRING_UTILS_INL_H__ |
||||
|
||||
#include <stdarg.h> |
||||
#include <wchar.h> |
||||
|
||||
#include <string> |
||||
|
||||
// The "ll" printf format size specifier corresponding to |long long| was
|
||||
// intrudced in MSVC8. Earlier versions did not provide this size specifier,
|
||||
// but "I64" can be used to print 64-bit types. Don't use "I64" where "ll"
|
||||
// is available, in the event of oddball systems where |long long| is not
|
||||
// 64 bits wide.
|
||||
#if _MSC_VER >= 1400 // MSVC 2005/8
|
||||
#define WIN_STRING_FORMAT_LL "ll" |
||||
#else // MSC_VER >= 1400
|
||||
#define WIN_STRING_FORMAT_LL "I64" |
||||
#endif // MSC_VER >= 1400
|
||||
|
||||
// A nonconforming version of swprintf, without the length argument, was
|
||||
// included with the CRT prior to MSVC8. Although a conforming version was
|
||||
// also available via an overload, it is not reliably chosen. _snwprintf
|
||||
// behaves as a standards-confirming swprintf should, so force the use of
|
||||
// _snwprintf when using older CRTs.
|
||||
#if _MSC_VER < 1400 // MSVC 2005/8
|
||||
#define swprintf _snwprintf |
||||
#else |
||||
// For MSVC8 and newer, swprintf_s is the recommended method. Conveniently,
|
||||
// it takes the same argument list as swprintf.
|
||||
#define swprintf swprintf_s |
||||
#endif // MSC_VER < 1400
|
||||
|
||||
namespace google_breakpad { |
||||
|
||||
using std::string; |
||||
using std::wstring; |
||||
|
||||
class WindowsStringUtils { |
||||
public: |
||||
// Roughly equivalent to MSVC8's wcscpy_s, except pre-MSVC8, this does
|
||||
// not fail if source is longer than destination_size. The destination
|
||||
// buffer is always 0-terminated.
|
||||
static void safe_wcscpy(wchar_t *destination, size_t destination_size, |
||||
const wchar_t *source); |
||||
|
||||
// Roughly equivalent to MSVC8's wcsncpy_s, except that _TRUNCATE cannot
|
||||
// be passed directly, and pre-MSVC8, this will not fail if source or count
|
||||
// are longer than destination_size. The destination buffer is always
|
||||
// 0-terminated.
|
||||
static void safe_wcsncpy(wchar_t *destination, size_t destination_size, |
||||
const wchar_t *source, size_t count); |
||||
|
||||
// Performs multi-byte to wide character conversion on C++ strings, using
|
||||
// mbstowcs_s (MSVC8) or mbstowcs (pre-MSVC8). Returns false on failure,
|
||||
// without setting wcs.
|
||||
static bool safe_mbstowcs(const string &mbs, wstring *wcs); |
||||
|
||||
// Returns the base name of a file, e.g. strips off the path.
|
||||
static wstring GetBaseName(const wstring &filename); |
||||
|
||||
private: |
||||
// Disallow instantiation and other object-based operations.
|
||||
WindowsStringUtils(); |
||||
WindowsStringUtils(const WindowsStringUtils&); |
||||
~WindowsStringUtils(); |
||||
void operator=(const WindowsStringUtils&); |
||||
}; |
||||
|
||||
// static
|
||||
inline void WindowsStringUtils::safe_wcscpy(wchar_t *destination, |
||||
size_t destination_size, |
||||
const wchar_t *source) { |
||||
#if _MSC_VER >= 1400 // MSVC 2005/8
|
||||
wcscpy_s(destination, destination_size, source); |
||||
#else // _MSC_VER >= 1400
|
||||
// Pre-MSVC 2005/8 doesn't have wcscpy_s. Simulate it with wcsncpy.
|
||||
// wcsncpy doesn't 0-terminate the destination buffer if the source string
|
||||
// is longer than size. Ensure that the destination is 0-terminated.
|
||||
wcsncpy(destination, source, destination_size); |
||||
if (destination && destination_size) |
||||
destination[destination_size - 1] = 0; |
||||
#endif // _MSC_VER >= 1400
|
||||
} |
||||
|
||||
// static
|
||||
inline void WindowsStringUtils::safe_wcsncpy(wchar_t *destination, |
||||
size_t destination_size, |
||||
const wchar_t *source, |
||||
size_t count) { |
||||
#if _MSC_VER >= 1400 // MSVC 2005/8
|
||||
wcsncpy_s(destination, destination_size, source, count); |
||||
#else // _MSC_VER >= 1400
|
||||
// Pre-MSVC 2005/8 doesn't have wcsncpy_s. Simulate it with wcsncpy.
|
||||
// wcsncpy doesn't 0-terminate the destination buffer if the source string
|
||||
// is longer than size. Ensure that the destination is 0-terminated.
|
||||
if (destination_size < count) |
||||
count = destination_size; |
||||
|
||||
wcsncpy(destination, source, count); |
||||
if (destination && count) |
||||
destination[count - 1] = 0; |
||||
#endif // _MSC_VER >= 1400
|
||||
} |
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // COMMON_WINDOWS_STRING_UTILS_INL_H__
|
@ -0,0 +1,83 @@ |
||||
/* Copyright (c) 2006, Google Inc.
|
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ |
||||
|
||||
/* breakpad_types.h: Precise-width types
|
||||
* |
||||
* (This is C99 source, please don't corrupt it with C++.) |
||||
* |
||||
* This file ensures that types u_intN_t are defined for N = 8, 16, 32, and |
||||
* 64. Types of precise widths are crucial to the task of writing data |
||||
* structures on one platform and reading them on another. |
||||
* |
||||
* Author: Mark Mentovai */ |
||||
|
||||
#ifndef GOOGLE_BREAKPAD_COMMON_BREAKPAD_TYPES_H__ |
||||
#define GOOGLE_BREAKPAD_COMMON_BREAKPAD_TYPES_H__ |
||||
|
||||
#ifndef _WIN32 |
||||
|
||||
#include <sys/types.h> |
||||
#ifndef __STDC_FORMAT_MACROS |
||||
#define __STDC_FORMAT_MACROS |
||||
#endif /* __STDC_FORMAT_MACROS */ |
||||
#include <inttypes.h> |
||||
|
||||
#if defined(__SUNPRO_CC) || (defined(__GNUC__) && defined(__sun__)) |
||||
typedef uint8_t u_int8_t; |
||||
typedef uint16_t u_int16_t; |
||||
typedef uint32_t u_int32_t; |
||||
typedef uint64_t u_int64_t; |
||||
#endif |
||||
|
||||
#else /* !_WIN32 */ |
||||
|
||||
#include <WTypes.h> |
||||
|
||||
typedef unsigned __int8 u_int8_t; |
||||
typedef unsigned __int16 u_int16_t; |
||||
typedef unsigned __int32 u_int32_t; |
||||
typedef unsigned __int64 u_int64_t; |
||||
|
||||
#endif /* !_WIN32 */ |
||||
|
||||
typedef struct { |
||||
u_int64_t high; |
||||
u_int64_t low; |
||||
} u_int128_t; |
||||
|
||||
typedef u_int64_t breakpad_time_t; |
||||
|
||||
/* Try to get PRIx64 from inttypes.h, but if it's not defined, fall back to
|
||||
* llx, which is the format string for "long long" - this is a 64-bit |
||||
* integral type on many systems. */ |
||||
#ifndef PRIx64 |
||||
#define PRIx64 "llx" |
||||
#endif /* !PRIx64 */ |
||||
|
||||
#endif /* GOOGLE_BREAKPAD_COMMON_BREAKPAD_TYPES_H__ */ |
@ -0,0 +1,231 @@ |
||||
/* Copyright (c) 2006, Google Inc.
|
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ |
||||
|
||||
/* minidump_format.h: A cross-platform reimplementation of minidump-related
|
||||
* portions of DbgHelp.h from the Windows Platform SDK. |
||||
* |
||||
* (This is C99 source, please don't corrupt it with C++.) |
||||
* |
||||
* This file contains the necessary definitions to read minidump files |
||||
* produced on amd64. These files may be read on any platform provided |
||||
* that the alignments of these structures on the processing system are |
||||
* identical to the alignments of these structures on the producing system. |
||||
* For this reason, precise-sized types are used. The structures defined |
||||
* by this file have been laid out to minimize alignment problems by ensuring |
||||
* ensuring that all members are aligned on their natural boundaries. In |
||||
* In some cases, tail-padding may be significant when different ABIs specify |
||||
* different tail-padding behaviors. To avoid problems when reading or |
||||
* writing affected structures, MD_*_SIZE macros are provided where needed, |
||||
* containing the useful size of the structures without padding. |
||||
* |
||||
* Structures that are defined by Microsoft to contain a zero-length array |
||||
* are instead defined here to contain an array with one element, as |
||||
* zero-length arrays are forbidden by standard C and C++. In these cases, |
||||
* *_minsize constants are provided to be used in place of sizeof. For a |
||||
* cleaner interface to these sizes when using C++, see minidump_size.h. |
||||
* |
||||
* These structures are also sufficient to populate minidump files. |
||||
* |
||||
* These definitions may be extended to support handling minidump files |
||||
* for other CPUs and other operating systems. |
||||
* |
||||
* Because precise data type sizes are crucial for this implementation to |
||||
* function properly and portably in terms of interoperability with minidumps |
||||
* produced by DbgHelp on Windows, a set of primitive types with known sizes |
||||
* are used as the basis of each structure defined by this file. DbgHelp |
||||
* on Windows is assumed to be the reference implementation; this file |
||||
* seeks to provide a cross-platform compatible implementation. To avoid |
||||
* collisions with the types and values defined and used by DbgHelp in the |
||||
* event that this implementation is used on Windows, each type and value |
||||
* defined here is given a new name, beginning with "MD". Names of the |
||||
* equivalent types and values in the Windows Platform SDK are given in |
||||
* comments. |
||||
* |
||||
* Author: Mark Mentovai
|
||||
* Change to split into its own file: Neal Sidhwaney */ |
||||
|
||||
#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_AMD64_H__ |
||||
#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_AMD64_H__ |
||||
|
||||
|
||||
/*
|
||||
* AMD64 support, see WINNT.H |
||||
*/ |
||||
|
||||
typedef struct { |
||||
u_int16_t control_word; |
||||
u_int16_t status_word; |
||||
u_int8_t tag_word; |
||||
u_int8_t reserved1; |
||||
u_int16_t error_opcode; |
||||
u_int32_t error_offset; |
||||
u_int16_t error_selector; |
||||
u_int16_t reserved2; |
||||
u_int32_t data_offset; |
||||
u_int16_t data_selector; |
||||
u_int16_t reserved3; |
||||
u_int32_t mx_csr; |
||||
u_int32_t mx_csr_mask; |
||||
u_int128_t float_registers[8]; |
||||
u_int128_t xmm_registers[16]; |
||||
u_int8_t reserved4[96]; |
||||
} MDXmmSaveArea32AMD64; /* XMM_SAVE_AREA32 */ |
||||
|
||||
#define MD_CONTEXT_AMD64_VR_COUNT 26 |
||||
|
||||
typedef struct { |
||||
/*
|
||||
* Register parameter home addresses. |
||||
*/ |
||||
u_int64_t p1_home; |
||||
u_int64_t p2_home; |
||||
u_int64_t p3_home; |
||||
u_int64_t p4_home; |
||||
u_int64_t p5_home; |
||||
u_int64_t p6_home; |
||||
|
||||
/* The next field determines the layout of the structure, and which parts
|
||||
* of it are populated */ |
||||
u_int32_t context_flags; |
||||
u_int32_t mx_csr; |
||||
|
||||
/* The next register is included with MD_CONTEXT_AMD64_CONTROL */ |
||||
u_int16_t cs; |
||||
|
||||
/* The next 4 registers are included with MD_CONTEXT_AMD64_SEGMENTS */ |
||||
u_int16_t ds; |
||||
u_int16_t es; |
||||
u_int16_t fs; |
||||
u_int16_t gs; |
||||
|
||||
/* The next 2 registers are included with MD_CONTEXT_AMD64_CONTROL */ |
||||
u_int16_t ss; |
||||
u_int32_t eflags; |
||||
|
||||
/* The next 6 registers are included with MD_CONTEXT_AMD64_DEBUG_REGISTERS */ |
||||
u_int64_t dr0; |
||||
u_int64_t dr1; |
||||
u_int64_t dr2; |
||||
u_int64_t dr3; |
||||
u_int64_t dr6; |
||||
u_int64_t dr7; |
||||
|
||||
/* The next 4 registers are included with MD_CONTEXT_AMD64_INTEGER */ |
||||
u_int64_t rax; |
||||
u_int64_t rcx; |
||||
u_int64_t rdx; |
||||
u_int64_t rbx; |
||||
|
||||
/* The next register is included with MD_CONTEXT_AMD64_CONTROL */ |
||||
u_int64_t rsp; |
||||
|
||||
/* The next 11 registers are included with MD_CONTEXT_AMD64_INTEGER */ |
||||
u_int64_t rbp; |
||||
u_int64_t rsi; |
||||
u_int64_t rdi; |
||||
u_int64_t r8; |
||||
u_int64_t r9; |
||||
u_int64_t r10; |
||||
u_int64_t r11; |
||||
u_int64_t r12; |
||||
u_int64_t r13; |
||||
u_int64_t r14; |
||||
u_int64_t r15; |
||||
|
||||
/* The next register is included with MD_CONTEXT_AMD64_CONTROL */ |
||||
u_int64_t rip; |
||||
|
||||
/* The next set of registers are included with
|
||||
* MD_CONTEXT_AMD64_FLOATING_POINT |
||||
*/ |
||||
union { |
||||
MDXmmSaveArea32AMD64 flt_save; |
||||
struct { |
||||
u_int128_t header[2]; |
||||
u_int128_t legacy[8]; |
||||
u_int128_t xmm0; |
||||
u_int128_t xmm1; |
||||
u_int128_t xmm2; |
||||
u_int128_t xmm3; |
||||
u_int128_t xmm4; |
||||
u_int128_t xmm5; |
||||
u_int128_t xmm6; |
||||
u_int128_t xmm7; |
||||
u_int128_t xmm8; |
||||
u_int128_t xmm9; |
||||
u_int128_t xmm10; |
||||
u_int128_t xmm11; |
||||
u_int128_t xmm12; |
||||
u_int128_t xmm13; |
||||
u_int128_t xmm14; |
||||
u_int128_t xmm15; |
||||
} sse_registers; |
||||
}; |
||||
|
||||
u_int128_t vector_register[MD_CONTEXT_AMD64_VR_COUNT]; |
||||
u_int64_t vector_control; |
||||
|
||||
/* The next 5 registers are included with MD_CONTEXT_AMD64_DEBUG_REGISTERS */ |
||||
u_int64_t debug_control; |
||||
u_int64_t last_branch_to_rip; |
||||
u_int64_t last_branch_from_rip; |
||||
u_int64_t last_exception_to_rip; |
||||
u_int64_t last_exception_from_rip; |
||||
|
||||
} MDRawContextAMD64; /* CONTEXT */ |
||||
|
||||
/* For (MDRawContextAMD64).context_flags. These values indicate the type of
|
||||
* context stored in the structure. The high 26 bits identify the CPU, the |
||||
* low 6 bits identify the type of context saved. */ |
||||
#define MD_CONTEXT_AMD64_CONTROL (MD_CONTEXT_AMD64 | 0x00000001) |
||||
/* CONTEXT_CONTROL */ |
||||
#define MD_CONTEXT_AMD64_INTEGER (MD_CONTEXT_AMD64 | 0x00000002) |
||||
/* CONTEXT_INTEGER */ |
||||
#define MD_CONTEXT_AMD64_SEGMENTS (MD_CONTEXT_AMD64 | 0x00000004) |
||||
/* CONTEXT_SEGMENTS */ |
||||
#define MD_CONTEXT_AMD64_FLOATING_POINT (MD_CONTEXT_AMD64 | 0x00000008) |
||||
/* CONTEXT_FLOATING_POINT */ |
||||
#define MD_CONTEXT_AMD64_DEBUG_REGISTERS (MD_CONTEXT_AMD64 | 0x00000010) |
||||
/* CONTEXT_DEBUG_REGISTERS */ |
||||
/* WinNT.h refers to CONTEXT_MMX_REGISTERS but doesn't appear to define it
|
||||
* I think it really means CONTEXT_FLOATING_POINT. |
||||
*/ |
||||
|
||||
#define MD_CONTEXT_AMD64_FULL (MD_CONTEXT_AMD64_CONTROL | \ |
||||
MD_CONTEXT_AMD64_INTEGER | \
|
||||
MD_CONTEXT_AMD64_FLOATING_POINT) |
||||
/* CONTEXT_FULL */ |
||||
|
||||
#define MD_CONTEXT_AMD64_ALL (MD_CONTEXT_AMD64_FULL | \ |
||||
MD_CONTEXT_AMD64_SEGMENTS | \
|
||||
MD_CONTEXT_X86_DEBUG_REGISTERS) |
||||
/* CONTEXT_ALL */ |
||||
|
||||
|
||||
#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_AMD64_H__ */ |
@ -0,0 +1,163 @@ |
||||
/* Copyright (c) 2006, Google Inc.
|
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ |
||||
|
||||
/* minidump_format.h: A cross-platform reimplementation of minidump-related
|
||||
* portions of DbgHelp.h from the Windows Platform SDK. |
||||
* |
||||
* (This is C99 source, please don't corrupt it with C++.) |
||||
* |
||||
* This file contains the necessary definitions to read minidump files |
||||
* produced on ppc. These files may be read on any platform provided |
||||
* that the alignments of these structures on the processing system are |
||||
* identical to the alignments of these structures on the producing system. |
||||
* For this reason, precise-sized types are used. The structures defined |
||||
* by this file have been laid out to minimize alignment problems by ensuring |
||||
* ensuring that all members are aligned on their natural boundaries. In |
||||
* In some cases, tail-padding may be significant when different ABIs specify |
||||
* different tail-padding behaviors. To avoid problems when reading or |
||||
* writing affected structures, MD_*_SIZE macros are provided where needed, |
||||
* containing the useful size of the structures without padding. |
||||
* |
||||
* Structures that are defined by Microsoft to contain a zero-length array |
||||
* are instead defined here to contain an array with one element, as |
||||
* zero-length arrays are forbidden by standard C and C++. In these cases, |
||||
* *_minsize constants are provided to be used in place of sizeof. For a |
||||
* cleaner interface to these sizes when using C++, see minidump_size.h. |
||||
* |
||||
* These structures are also sufficient to populate minidump files. |
||||
* |
||||
* These definitions may be extended to support handling minidump files |
||||
* for other CPUs and other operating systems. |
||||
* |
||||
* Because precise data type sizes are crucial for this implementation to |
||||
* function properly and portably in terms of interoperability with minidumps |
||||
* produced by DbgHelp on Windows, a set of primitive types with known sizes |
||||
* are used as the basis of each structure defined by this file. DbgHelp |
||||
* on Windows is assumed to be the reference implementation; this file |
||||
* seeks to provide a cross-platform compatible implementation. To avoid |
||||
* collisions with the types and values defined and used by DbgHelp in the |
||||
* event that this implementation is used on Windows, each type and value |
||||
* defined here is given a new name, beginning with "MD". Names of the |
||||
* equivalent types and values in the Windows Platform SDK are given in |
||||
* comments. |
||||
* |
||||
* Author: Mark Mentovai
|
||||
* Change to split into its own file: Neal Sidhwaney */ |
||||
|
||||
/*
|
||||
* Breakpad minidump extension for PowerPC support. Based on Darwin/Mac OS X' |
||||
* mach/ppc/_types.h |
||||
*/ |
||||
|
||||
#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_PPC_H__ |
||||
#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_PPC_H__ |
||||
|
||||
#define MD_FLOATINGSAVEAREA_PPC_FPR_COUNT 32 |
||||
|
||||
typedef struct { |
||||
/* fpregs is a double[32] in mach/ppc/_types.h, but a u_int64_t is used
|
||||
* here for precise sizing. */ |
||||
u_int64_t fpregs[MD_FLOATINGSAVEAREA_PPC_FPR_COUNT]; |
||||
u_int32_t fpscr_pad; |
||||
u_int32_t fpscr; /* Status/control */ |
||||
} MDFloatingSaveAreaPPC; /* Based on ppc_float_state */ |
||||
|
||||
|
||||
#define MD_VECTORSAVEAREA_PPC_VR_COUNT 32 |
||||
|
||||
typedef struct { |
||||
/* Vector registers (including vscr) are 128 bits, but mach/ppc/_types.h
|
||||
* exposes them as four 32-bit quantities. */ |
||||
u_int128_t save_vr[MD_VECTORSAVEAREA_PPC_VR_COUNT]; |
||||
u_int128_t save_vscr; /* Status/control */ |
||||
u_int32_t save_pad5[4]; |
||||
u_int32_t save_vrvalid; /* Identifies which vector registers are saved */ |
||||
u_int32_t save_pad6[7]; |
||||
} MDVectorSaveAreaPPC; /* ppc_vector_state */ |
||||
|
||||
|
||||
#define MD_CONTEXT_PPC_GPR_COUNT 32 |
||||
|
||||
/* Use the same 32-bit alignment when accessing this structure from 64-bit code
|
||||
* as is used natively in 32-bit code. #pragma pack is a MSVC extension |
||||
* supported by gcc. */ |
||||
#if defined(__SUNPRO_C) || defined(__SUNPRO_CC) |
||||
#pragma pack(4) |
||||
#else |
||||
#pragma pack(push, 4) |
||||
#endif |
||||
|
||||
typedef struct { |
||||
/* context_flags is not present in ppc_thread_state, but it aids
|
||||
* identification of MDRawContextPPC among other raw context types, |
||||
* and it guarantees alignment when we get to float_save. */ |
||||
u_int32_t context_flags; |
||||
|
||||
u_int32_t srr0; /* Machine status save/restore: stores pc
|
||||
* (instruction) */ |
||||
u_int32_t srr1; /* Machine status save/restore: stores msr
|
||||
* (ps, program/machine state) */ |
||||
/* ppc_thread_state contains 32 fields, r0 .. r31. Here, an array is
|
||||
* used for brevity. */ |
||||
u_int32_t gpr[MD_CONTEXT_PPC_GPR_COUNT]; |
||||
u_int32_t cr; /* Condition */ |
||||
u_int32_t xer; /* Integer (fiXed-point) exception */ |
||||
u_int32_t lr; /* Link */ |
||||
u_int32_t ctr; /* Count */ |
||||
u_int32_t mq; /* Multiply/Quotient (PPC 601, POWER only) */ |
||||
u_int32_t vrsave; /* Vector save */ |
||||
|
||||
/* float_save and vector_save aren't present in ppc_thread_state, but
|
||||
* are represented in separate structures that still define a thread's |
||||
* context. */ |
||||
MDFloatingSaveAreaPPC float_save; |
||||
MDVectorSaveAreaPPC vector_save; |
||||
} MDRawContextPPC; /* Based on ppc_thread_state */ |
||||
|
||||
#if defined(__SUNPRO_C) || defined(__SUNPRO_CC) |
||||
#pragma pack(0) |
||||
#else |
||||
#pragma pack(pop) |
||||
#endif |
||||
|
||||
/* For (MDRawContextPPC).context_flags. These values indicate the type of
|
||||
* context stored in the structure. MD_CONTEXT_PPC is Breakpad-defined. Its |
||||
* value was chosen to avoid likely conflicts with MD_CONTEXT_* for other |
||||
* CPUs. */ |
||||
#define MD_CONTEXT_PPC 0x20000000 |
||||
#define MD_CONTEXT_PPC_BASE (MD_CONTEXT_PPC | 0x00000001) |
||||
#define MD_CONTEXT_PPC_FLOATING_POINT (MD_CONTEXT_PPC | 0x00000008) |
||||
#define MD_CONTEXT_PPC_VECTOR (MD_CONTEXT_PPC | 0x00000020) |
||||
|
||||
#define MD_CONTEXT_PPC_FULL MD_CONTEXT_PPC_BASE |
||||
#define MD_CONTEXT_PPC_ALL (MD_CONTEXT_PPC_FULL | \ |
||||
MD_CONTEXT_PPC_FLOATING_POINT | \
|
||||
MD_CONTEXT_PPC_VECTOR) |
||||
|
||||
#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_PPC_H__ */ |
@ -0,0 +1,129 @@ |
||||
/* Copyright (c) 2008, Google Inc.
|
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ |
||||
|
||||
/* minidump_format.h: A cross-platform reimplementation of minidump-related
|
||||
* portions of DbgHelp.h from the Windows Platform SDK. |
||||
* |
||||
* (This is C99 source, please don't corrupt it with C++.) |
||||
* |
||||
* This file contains the necessary definitions to read minidump files |
||||
* produced on ppc64. These files may be read on any platform provided |
||||
* that the alignments of these structures on the processing system are |
||||
* identical to the alignments of these structures on the producing system. |
||||
* For this reason, precise-sized types are used. The structures defined |
||||
* by this file have been laid out to minimize alignment problems by ensuring |
||||
* ensuring that all members are aligned on their natural boundaries. In |
||||
* In some cases, tail-padding may be significant when different ABIs specify |
||||
* different tail-padding behaviors. To avoid problems when reading or |
||||
* writing affected structures, MD_*_SIZE macros are provided where needed, |
||||
* containing the useful size of the structures without padding. |
||||
* |
||||
* Structures that are defined by Microsoft to contain a zero-length array |
||||
* are instead defined here to contain an array with one element, as |
||||
* zero-length arrays are forbidden by standard C and C++. In these cases, |
||||
* *_minsize constants are provided to be used in place of sizeof. For a |
||||
* cleaner interface to these sizes when using C++, see minidump_size.h. |
||||
* |
||||
* These structures are also sufficient to populate minidump files. |
||||
* |
||||
* These definitions may be extended to support handling minidump files |
||||
* for other CPUs and other operating systems. |
||||
* |
||||
* Because precise data type sizes are crucial for this implementation to |
||||
* function properly and portably in terms of interoperability with minidumps |
||||
* produced by DbgHelp on Windows, a set of primitive types with known sizes |
||||
* are used as the basis of each structure defined by this file. DbgHelp |
||||
* on Windows is assumed to be the reference implementation; this file |
||||
* seeks to provide a cross-platform compatible implementation. To avoid |
||||
* collisions with the types and values defined and used by DbgHelp in the |
||||
* event that this implementation is used on Windows, each type and value |
||||
* defined here is given a new name, beginning with "MD". Names of the |
||||
* equivalent types and values in the Windows Platform SDK are given in |
||||
* comments. |
||||
* |
||||
* Author: Neal Sidhwaney */ |
||||
|
||||
|
||||
/*
|
||||
* Breakpad minidump extension for PPC64 support. Based on Darwin/Mac OS X' |
||||
* mach/ppc/_types.h |
||||
*/ |
||||
|
||||
#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_PPC64_H__ |
||||
#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_PPC64_H__ |
||||
|
||||
#include "minidump_cpu_ppc.h" |
||||
|
||||
// these types are the same in ppc64 & ppc
|
||||
typedef MDFloatingSaveAreaPPC MDFloatingSaveAreaPPC64; |
||||
typedef MDVectorSaveAreaPPC MDVectorSaveAreaPPC64; |
||||
|
||||
#define MD_CONTEXT_PPC64_GPR_COUNT MD_CONTEXT_PPC_GPR_COUNT |
||||
|
||||
typedef struct { |
||||
/* context_flags is not present in ppc_thread_state, but it aids
|
||||
* identification of MDRawContextPPC among other raw context types, |
||||
* and it guarantees alignment when we get to float_save. */ |
||||
u_int64_t context_flags; |
||||
|
||||
u_int64_t srr0; /* Machine status save/restore: stores pc
|
||||
* (instruction) */ |
||||
u_int64_t srr1; /* Machine status save/restore: stores msr
|
||||
* (ps, program/machine state) */ |
||||
/* ppc_thread_state contains 32 fields, r0 .. r31. Here, an array is
|
||||
* used for brevity. */ |
||||
u_int64_t gpr[MD_CONTEXT_PPC64_GPR_COUNT]; |
||||
u_int64_t cr; /* Condition */ |
||||
u_int64_t xer; /* Integer (fiXed-point) exception */ |
||||
u_int64_t lr; /* Link */ |
||||
u_int64_t ctr; /* Count */ |
||||
u_int64_t vrsave; /* Vector save */ |
||||
|
||||
/* float_save and vector_save aren't present in ppc_thread_state, but
|
||||
* are represented in separate structures that still define a thread's |
||||
* context. */ |
||||
MDFloatingSaveAreaPPC float_save; |
||||
MDVectorSaveAreaPPC vector_save; |
||||
} MDRawContextPPC64; /* Based on ppc_thread_state */ |
||||
|
||||
/* For (MDRawContextPPC).context_flags. These values indicate the type of
|
||||
* context stored in the structure. MD_CONTEXT_PPC is Breakpad-defined. Its |
||||
* value was chosen to avoid likely conflicts with MD_CONTEXT_* for other |
||||
* CPUs. */ |
||||
#define MD_CONTEXT_PPC 0x20000000 |
||||
#define MD_CONTEXT_PPC_BASE (MD_CONTEXT_PPC | 0x00000001) |
||||
#define MD_CONTEXT_PPC_FLOATING_POINT (MD_CONTEXT_PPC | 0x00000008) |
||||
#define MD_CONTEXT_PPC_VECTOR (MD_CONTEXT_PPC | 0x00000020) |
||||
|
||||
#define MD_CONTEXT_PPC_FULL MD_CONTEXT_PPC_BASE |
||||
#define MD_CONTEXT_PPC_ALL (MD_CONTEXT_PPC_FULL | \ |
||||
MD_CONTEXT_PPC_FLOATING_POINT | \
|
||||
MD_CONTEXT_PPC_VECTOR) |
||||
|
||||
#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_PPC64_H__ */ |
@ -0,0 +1,158 @@ |
||||
/* Copyright (c) 2006, Google Inc.
|
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ |
||||
|
||||
/* minidump_format.h: A cross-platform reimplementation of minidump-related
|
||||
* portions of DbgHelp.h from the Windows Platform SDK. |
||||
* |
||||
* (This is C99 source, please don't corrupt it with C++.) |
||||
* |
||||
* This file contains the necessary definitions to read minidump files |
||||
* produced on sparc. These files may be read on any platform provided |
||||
* that the alignments of these structures on the processing system are |
||||
* identical to the alignments of these structures on the producing system. |
||||
* For this reason, precise-sized types are used. The structures defined |
||||
* by this file have been laid out to minimize alignment problems by ensuring |
||||
* ensuring that all members are aligned on their natural boundaries. In |
||||
* In some cases, tail-padding may be significant when different ABIs specify |
||||
* different tail-padding behaviors. To avoid problems when reading or |
||||
* writing affected structures, MD_*_SIZE macros are provided where needed, |
||||
* containing the useful size of the structures without padding. |
||||
* |
||||
* Structures that are defined by Microsoft to contain a zero-length array |
||||
* are instead defined here to contain an array with one element, as |
||||
* zero-length arrays are forbidden by standard C and C++. In these cases, |
||||
* *_minsize constants are provided to be used in place of sizeof. For a |
||||
* cleaner interface to these sizes when using C++, see minidump_size.h. |
||||
* |
||||
* These structures are also sufficient to populate minidump files. |
||||
* |
||||
* These definitions may be extended to support handling minidump files |
||||
* for other CPUs and other operating systems. |
||||
* |
||||
* Because precise data type sizes are crucial for this implementation to |
||||
* function properly and portably in terms of interoperability with minidumps |
||||
* produced by DbgHelp on Windows, a set of primitive types with known sizes |
||||
* are used as the basis of each structure defined by this file. DbgHelp |
||||
* on Windows is assumed to be the reference implementation; this file |
||||
* seeks to provide a cross-platform compatible implementation. To avoid |
||||
* collisions with the types and values defined and used by DbgHelp in the |
||||
* event that this implementation is used on Windows, each type and value |
||||
* defined here is given a new name, beginning with "MD". Names of the |
||||
* equivalent types and values in the Windows Platform SDK are given in |
||||
* comments. |
||||
* |
||||
* Author: Mark Mentovai |
||||
* Change to split into its own file: Neal Sidhwaney */ |
||||
|
||||
/*
|
||||
* SPARC support, see (solaris)sys/procfs_isa.h also |
||||
*/ |
||||
|
||||
#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_SPARC_H__ |
||||
#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_SPARC_H__ |
||||
|
||||
#define MD_FLOATINGSAVEAREA_SPARC_FPR_COUNT 32 |
||||
|
||||
typedef struct { |
||||
|
||||
/* FPU floating point regs */ |
||||
u_int64_t regs[MD_FLOATINGSAVEAREA_SPARC_FPR_COUNT]; |
||||
|
||||
u_int64_t filler; |
||||
u_int64_t fsr; /* FPU status register */ |
||||
} MDFloatingSaveAreaSPARC; /* FLOATING_SAVE_AREA */ |
||||
|
||||
#define MD_CONTEXT_SPARC_GPR_COUNT 32 |
||||
|
||||
typedef struct { |
||||
/* The next field determines the layout of the structure, and which parts
|
||||
* of it are populated |
||||
*/ |
||||
u_int32_t context_flags; |
||||
u_int32_t flag_pad; |
||||
/*
|
||||
* General register access (SPARC). |
||||
* Don't confuse definitions here with definitions in <sys/regset.h>. |
||||
* Registers are 32 bits for ILP32, 64 bits for LP64. |
||||
* SPARC V7/V8 is for 32bit, SPARC V9 is for 64bit |
||||
*/ |
||||
|
||||
/* 32 Integer working registers */ |
||||
|
||||
/* g_r[0-7] global registers(g0-g7)
|
||||
* g_r[8-15] out registers(o0-o7) |
||||
* g_r[16-23] local registers(l0-l7) |
||||
* g_r[24-31] in registers(i0-i7) |
||||
*/ |
||||
u_int64_t g_r[MD_CONTEXT_SPARC_GPR_COUNT]; |
||||
|
||||
/* several control registers */ |
||||
|
||||
/* Processor State register(PSR) for SPARC V7/V8
|
||||
* Condition Code register (CCR) for SPARC V9 |
||||
*/ |
||||
u_int64_t ccr; |
||||
|
||||
u_int64_t pc; /* Program Counter register (PC) */ |
||||
u_int64_t npc; /* Next Program Counter register (nPC) */ |
||||
u_int64_t y; /* Y register (Y) */ |
||||
|
||||
/* Address Space Identifier register (ASI) for SPARC V9
|
||||
* WIM for SPARC V7/V8 |
||||
*/ |
||||
u_int64_t asi; |
||||
|
||||
/* Floating-Point Registers State register (FPRS) for SPARC V9
|
||||
* TBR for for SPARC V7/V8 |
||||
*/ |
||||
u_int64_t fprs; |
||||
|
||||
/* The next field is included with MD_CONTEXT_SPARC_FLOATING_POINT */ |
||||
MDFloatingSaveAreaSPARC float_save; |
||||
|
||||
} MDRawContextSPARC; /* CONTEXT_SPARC */ |
||||
|
||||
/* For (MDRawContextSPARC).context_flags. These values indicate the type of
|
||||
* context stored in the structure. MD_CONTEXT_SPARC is Breakpad-defined. Its |
||||
* value was chosen to avoid likely conflicts with MD_CONTEXT_* for other |
||||
* CPUs. */ |
||||
#define MD_CONTEXT_SPARC 0x10000000 |
||||
#define MD_CONTEXT_SPARC_CONTROL (MD_CONTEXT_SPARC | 0x00000001) |
||||
#define MD_CONTEXT_SPARC_INTEGER (MD_CONTEXT_SPARC | 0x00000002) |
||||
#define MD_CONTEXT_SAPARC_FLOATING_POINT (MD_CONTEXT_SPARC | 0x00000004) |
||||
#define MD_CONTEXT_SAPARC_EXTRA (MD_CONTEXT_SPARC | 0x00000008) |
||||
|
||||
#define MD_CONTEXT_SPARC_FULL (MD_CONTEXT_SPARC_CONTROL | \ |
||||
MD_CONTEXT_SPARC_INTEGER) |
||||
|
||||
#define MD_CONTEXT_SPARC_ALL (MD_CONTEXT_SPARC_FULL | \ |
||||
MD_CONTEXT_SAPARC_FLOATING_POINT | \
|
||||
MD_CONTEXT_SAPARC_EXTRA) |
||||
|
||||
#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_SPARC_H__ */ |
@ -0,0 +1,172 @@ |
||||
/* Copyright (c) 2006, Google Inc.
|
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ |
||||
|
||||
/* minidump_format.h: A cross-platform reimplementation of minidump-related
|
||||
* portions of DbgHelp.h from the Windows Platform SDK. |
||||
* |
||||
* (This is C99 source, please don't corrupt it with C++.) |
||||
* |
||||
* This file contains the necessary definitions to read minidump files |
||||
* produced on x86. These files may be read on any platform provided |
||||
* that the alignments of these structures on the processing system are |
||||
* identical to the alignments of these structures on the producing system. |
||||
* For this reason, precise-sized types are used. The structures defined |
||||
* by this file have been laid out to minimize alignment problems by ensuring |
||||
* ensuring that all members are aligned on their natural boundaries. In |
||||
* In some cases, tail-padding may be significant when different ABIs specify |
||||
* different tail-padding behaviors. To avoid problems when reading or |
||||
* writing affected structures, MD_*_SIZE macros are provided where needed, |
||||
* containing the useful size of the structures without padding. |
||||
* |
||||
* Structures that are defined by Microsoft to contain a zero-length array |
||||
* are instead defined here to contain an array with one element, as |
||||
* zero-length arrays are forbidden by standard C and C++. In these cases, |
||||
* *_minsize constants are provided to be used in place of sizeof. For a |
||||
* cleaner interface to these sizes when using C++, see minidump_size.h. |
||||
* |
||||
* These structures are also sufficient to populate minidump files. |
||||
* |
||||
* These definitions may be extended to support handling minidump files |
||||
* for other CPUs and other operating systems. |
||||
* |
||||
* Because precise data type sizes are crucial for this implementation to |
||||
* function properly and portably in terms of interoperability with minidumps |
||||
* produced by DbgHelp on Windows, a set of primitive types with known sizes |
||||
* are used as the basis of each structure defined by this file. DbgHelp |
||||
* on Windows is assumed to be the reference implementation; this file |
||||
* seeks to provide a cross-platform compatible implementation. To avoid |
||||
* collisions with the types and values defined and used by DbgHelp in the |
||||
* event that this implementation is used on Windows, each type and value |
||||
* defined here is given a new name, beginning with "MD". Names of the |
||||
* equivalent types and values in the Windows Platform SDK are given in |
||||
* comments. |
||||
* |
||||
* Author: Mark Mentovai */ |
||||
|
||||
#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_X86_H__ |
||||
#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_X86_H__ |
||||
|
||||
#define MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE 80 |
||||
/* SIZE_OF_80387_REGISTERS */ |
||||
|
||||
typedef struct { |
||||
u_int32_t control_word; |
||||
u_int32_t status_word; |
||||
u_int32_t tag_word; |
||||
u_int32_t error_offset; |
||||
u_int32_t error_selector; |
||||
u_int32_t data_offset; |
||||
u_int32_t data_selector; |
||||
|
||||
/* register_area contains eight 80-bit (x87 "long double") quantities for
|
||||
* floating-point registers %st0 (%mm0) through %st7 (%mm7). */ |
||||
u_int8_t register_area[MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE]; |
||||
u_int32_t cr0_npx_state; |
||||
} MDFloatingSaveAreaX86; /* FLOATING_SAVE_AREA */ |
||||
|
||||
|
||||
#define MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE 512 |
||||
/* MAXIMUM_SUPPORTED_EXTENSION */ |
||||
|
||||
typedef struct { |
||||
/* The next field determines the layout of the structure, and which parts
|
||||
* of it are populated */ |
||||
u_int32_t context_flags; |
||||
|
||||
/* The next 6 registers are included with MD_CONTEXT_X86_DEBUG_REGISTERS */ |
||||
u_int32_t dr0; |
||||
u_int32_t dr1; |
||||
u_int32_t dr2; |
||||
u_int32_t dr3; |
||||
u_int32_t dr6; |
||||
u_int32_t dr7; |
||||
|
||||
/* The next field is included with MD_CONTEXT_X86_FLOATING_POINT */ |
||||
MDFloatingSaveAreaX86 float_save; |
||||
|
||||
/* The next 4 registers are included with MD_CONTEXT_X86_SEGMENTS */ |
||||
u_int32_t gs;
|
||||
u_int32_t fs; |
||||
u_int32_t es; |
||||
u_int32_t ds; |
||||
/* The next 6 registers are included with MD_CONTEXT_X86_INTEGER */ |
||||
u_int32_t edi; |
||||
u_int32_t esi; |
||||
u_int32_t ebx; |
||||
u_int32_t edx; |
||||
u_int32_t ecx; |
||||
u_int32_t eax; |
||||
|
||||
/* The next 6 registers are included with MD_CONTEXT_X86_CONTROL */ |
||||
u_int32_t ebp; |
||||
u_int32_t eip; |
||||
u_int32_t cs; /* WinNT.h says "must be sanitized" */ |
||||
u_int32_t eflags; /* WinNT.h says "must be sanitized" */ |
||||
u_int32_t esp; |
||||
u_int32_t ss; |
||||
|
||||
/* The next field is included with MD_CONTEXT_X86_EXTENDED_REGISTERS.
|
||||
* It contains vector (MMX/SSE) registers. It it laid out in the |
||||
* format used by the fxsave and fsrstor instructions, so it includes |
||||
* a copy of the x87 floating-point registers as well. See FXSAVE in |
||||
* "Intel Architecture Software Developer's Manual, Volume 2." */ |
||||
u_int8_t extended_registers[ |
||||
MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE]; |
||||
} MDRawContextX86; /* CONTEXT */ |
||||
|
||||
/* For (MDRawContextX86).context_flags. These values indicate the type of
|
||||
* context stored in the structure. The high 26 bits identify the CPU, the |
||||
* low 6 bits identify the type of context saved. */ |
||||
#define MD_CONTEXT_X86 0x00010000 |
||||
/* CONTEXT_i386, CONTEXT_i486: identifies CPU */ |
||||
#define MD_CONTEXT_X86_CONTROL (MD_CONTEXT_X86 | 0x00000001) |
||||
/* CONTEXT_CONTROL */ |
||||
#define MD_CONTEXT_X86_INTEGER (MD_CONTEXT_X86 | 0x00000002) |
||||
/* CONTEXT_INTEGER */ |
||||
#define MD_CONTEXT_X86_SEGMENTS (MD_CONTEXT_X86 | 0x00000004) |
||||
/* CONTEXT_SEGMENTS */ |
||||
#define MD_CONTEXT_X86_FLOATING_POINT (MD_CONTEXT_X86 | 0x00000008) |
||||
/* CONTEXT_FLOATING_POINT */ |
||||
#define MD_CONTEXT_X86_DEBUG_REGISTERS (MD_CONTEXT_X86 | 0x00000010) |
||||
/* CONTEXT_DEBUG_REGISTERS */ |
||||
#define MD_CONTEXT_X86_EXTENDED_REGISTERS (MD_CONTEXT_X86 | 0x00000020) |
||||
/* CONTEXT_EXTENDED_REGISTERS */ |
||||
|
||||
#define MD_CONTEXT_X86_FULL (MD_CONTEXT_X86_CONTROL | \ |
||||
MD_CONTEXT_X86_INTEGER | \
|
||||
MD_CONTEXT_X86_SEGMENTS) |
||||
/* CONTEXT_FULL */ |
||||
|
||||
#define MD_CONTEXT_X86_ALL (MD_CONTEXT_X86_FULL | \ |
||||
MD_CONTEXT_X86_FLOATING_POINT | \
|
||||
MD_CONTEXT_X86_DEBUG_REGISTERS | \
|
||||
MD_CONTEXT_X86_EXTENDED_REGISTERS) |
||||
/* CONTEXT_ALL */ |
||||
|
||||
#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_X86_H__ */ |
@ -0,0 +1,85 @@ |
||||
/* Copyright (c) 2006, Google Inc.
|
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ |
||||
|
||||
/* minidump_exception_linux.h: A definition of exception codes for
|
||||
* Linux |
||||
* |
||||
* (This is C99 source, please don't corrupt it with C++.) |
||||
* |
||||
* Author: Mark Mentovai |
||||
* Split into its own file: Neal Sidhwaney */ |
||||
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_LINUX_H__ |
||||
#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_LINUX_H__ |
||||
|
||||
#include <stddef.h> |
||||
|
||||
#include "google_breakpad/common/breakpad_types.h" |
||||
|
||||
|
||||
/* For (MDException).exception_code. These values come from bits/signum.h.
|
||||
*/ |
||||
typedef enum { |
||||
MD_EXCEPTION_CODE_LIN_SIGHUP = 1, /* Hangup (POSIX) */ |
||||
MD_EXCEPTION_CODE_LIN_SIGINT = 2, /* Interrupt (ANSI) */ |
||||
MD_EXCEPTION_CODE_LIN_SIGQUIT = 3, /* Quit (POSIX) */ |
||||
MD_EXCEPTION_CODE_LIN_SIGILL = 4, /* Illegal instruction (ANSI) */ |
||||
MD_EXCEPTION_CODE_LIN_SIGTRAP = 5, /* Trace trap (POSIX) */ |
||||
MD_EXCEPTION_CODE_LIN_SIGABRT = 6, /* Abort (ANSI) */ |
||||
MD_EXCEPTION_CODE_LIN_SIGBUS = 7, /* BUS error (4.2 BSD) */ |
||||
MD_EXCEPTION_CODE_LIN_SIGFPE = 8, /* Floating-point exception (ANSI) */ |
||||
MD_EXCEPTION_CODE_LIN_SIGKILL = 9, /* Kill, unblockable (POSIX) */ |
||||
MD_EXCEPTION_CODE_LIN_SIGUSR1 = 10, /* User-defined signal 1 (POSIX). */ |
||||
MD_EXCEPTION_CODE_LIN_SIGSEGV = 11, /* Segmentation violation (ANSI) */ |
||||
MD_EXCEPTION_CODE_LIN_SIGUSR2 = 12, /* User-defined signal 2 (POSIX) */ |
||||
MD_EXCEPTION_CODE_LIN_SIGPIPE = 13, /* Broken pipe (POSIX) */ |
||||
MD_EXCEPTION_CODE_LIN_SIGALRM = 14, /* Alarm clock (POSIX) */ |
||||
MD_EXCEPTION_CODE_LIN_SIGTERM = 15, /* Termination (ANSI) */ |
||||
MD_EXCEPTION_CODE_LIN_SIGSTKFLT = 16, /* Stack faultd */ |
||||
MD_EXCEPTION_CODE_LIN_SIGCHLD = 17, /* Child status has changed (POSIX) */ |
||||
MD_EXCEPTION_CODE_LIN_SIGCONT = 18, /* Continue (POSIX) */ |
||||
MD_EXCEPTION_CODE_LIN_SIGSTOP = 19, /* Stop, unblockable (POSIX) */ |
||||
MD_EXCEPTION_CODE_LIN_SIGTSTP = 20, /* Keyboard stop (POSIX) */ |
||||
MD_EXCEPTION_CODE_LIN_SIGTTIN = 21, /* Background read from tty (POSIX) */ |
||||
MD_EXCEPTION_CODE_LIN_SIGTTOU = 22, /* Background write to tty (POSIX) */ |
||||
MD_EXCEPTION_CODE_LIN_SIGURG = 23, |
||||
/* Urgent condition on socket (4.2 BSD) */ |
||||
MD_EXCEPTION_CODE_LIN_SIGXCPU = 24, /* CPU limit exceeded (4.2 BSD) */ |
||||
MD_EXCEPTION_CODE_LIN_SIGXFSZ = 25, |
||||
/* File size limit exceeded (4.2 BSD) */ |
||||
MD_EXCEPTION_CODE_LIN_SIGVTALRM = 26, /* Virtual alarm clock (4.2 BSD) */ |
||||
MD_EXCEPTION_CODE_LIN_SIGPROF = 27, /* Profiling alarm clock (4.2 BSD) */ |
||||
MD_EXCEPTION_CODE_LIN_SIGWINCH = 28, /* Window size change (4.3 BSD, Sun) */ |
||||
MD_EXCEPTION_CODE_LIN_SIGIO = 29, /* I/O now possible (4.2 BSD) */ |
||||
MD_EXCEPTION_CODE_LIN_SIGPWR = 30, /* Power failure restart (System V) */ |
||||
MD_EXCEPTION_CODE_LIN_SIGSYS = 31 /* Bad system call */ |
||||
} MDExceptionCodeLinux; |
||||
|
||||
#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_LINUX_H__ */ |
@ -0,0 +1,193 @@ |
||||
/* Copyright (c) 2006, Google Inc.
|
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ |
||||
|
||||
/* minidump_exception_mac.h: A definition of exception codes for Mac
|
||||
* OS X |
||||
* |
||||
* (This is C99 source, please don't corrupt it with C++.) |
||||
* |
||||
* Author: Mark Mentovai |
||||
* Split into its own file: Neal Sidhwaney */ |
||||
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_MAC_H__ |
||||
#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_MAC_H__ |
||||
|
||||
#include <stddef.h> |
||||
|
||||
#include "google_breakpad/common/breakpad_types.h" |
||||
|
||||
/* For (MDException).exception_code. Breakpad minidump extension for Mac OS X
|
||||
* support. Based on Darwin/Mac OS X' mach/exception_types.h. This is |
||||
* what Mac OS X calls an "exception", not a "code". */ |
||||
typedef enum { |
||||
/* Exception code. The high 16 bits of exception_code contains one of
|
||||
* these values. */ |
||||
MD_EXCEPTION_MAC_BAD_ACCESS = 1, /* code can be a kern_return_t */ |
||||
/* EXC_BAD_ACCESS */ |
||||
MD_EXCEPTION_MAC_BAD_INSTRUCTION = 2, /* code is CPU-specific */ |
||||
/* EXC_BAD_INSTRUCTION */ |
||||
MD_EXCEPTION_MAC_ARITHMETIC = 3, /* code is CPU-specific */ |
||||
/* EXC_ARITHMETIC */ |
||||
MD_EXCEPTION_MAC_EMULATION = 4, /* code is CPU-specific */ |
||||
/* EXC_EMULATION */ |
||||
MD_EXCEPTION_MAC_SOFTWARE = 5, |
||||
/* EXC_SOFTWARE */ |
||||
MD_EXCEPTION_MAC_BREAKPOINT = 6, /* code is CPU-specific */ |
||||
/* EXC_BREAKPOINT */ |
||||
MD_EXCEPTION_MAC_SYSCALL = 7, |
||||
/* EXC_SYSCALL */ |
||||
MD_EXCEPTION_MAC_MACH_SYSCALL = 8, |
||||
/* EXC_MACH_SYSCALL */ |
||||
MD_EXCEPTION_MAC_RPC_ALERT = 9 |
||||
/* EXC_RPC_ALERT */ |
||||
} MDExceptionMac; |
||||
|
||||
/* For (MDException).exception_flags. Breakpad minidump extension for Mac OS X
|
||||
* support. Based on Darwin/Mac OS X' mach/ppc/exception.h and |
||||
* mach/i386/exception.h. This is what Mac OS X calls a "code". */ |
||||
typedef enum { |
||||
/* With MD_EXCEPTION_BAD_ACCESS. These are relevant kern_return_t values
|
||||
* from mach/kern_return.h. */ |
||||
MD_EXCEPTION_CODE_MAC_INVALID_ADDRESS = 1, |
||||
/* KERN_INVALID_ADDRESS */ |
||||
MD_EXCEPTION_CODE_MAC_PROTECTION_FAILURE = 2, |
||||
/* KERN_PROTECTION_FAILURE */ |
||||
MD_EXCEPTION_CODE_MAC_NO_ACCESS = 8, |
||||
/* KERN_NO_ACCESS */ |
||||
MD_EXCEPTION_CODE_MAC_MEMORY_FAILURE = 9, |
||||
/* KERN_MEMORY_FAILURE */ |
||||
MD_EXCEPTION_CODE_MAC_MEMORY_ERROR = 10, |
||||
/* KERN_MEMORY_ERROR */ |
||||
|
||||
/* With MD_EXCEPTION_SOFTWARE */ |
||||
MD_EXCEPTION_CODE_MAC_BAD_SYSCALL = 0x00010000, /* Mach SIGSYS */ |
||||
MD_EXCEPTION_CODE_MAC_BAD_PIPE = 0x00010001, /* Mach SIGPIPE */ |
||||
MD_EXCEPTION_CODE_MAC_ABORT = 0x00010002, /* Mach SIGABRT */ |
||||
|
||||
/* With MD_EXCEPTION_MAC_BAD_ACCESS on ppc */ |
||||
MD_EXCEPTION_CODE_MAC_PPC_VM_PROT_READ = 0x0101, |
||||
/* EXC_PPC_VM_PROT_READ */ |
||||
MD_EXCEPTION_CODE_MAC_PPC_BADSPACE = 0x0102, |
||||
/* EXC_PPC_BADSPACE */ |
||||
MD_EXCEPTION_CODE_MAC_PPC_UNALIGNED = 0x0103, |
||||
/* EXC_PPC_UNALIGNED */ |
||||
|
||||
/* With MD_EXCEPTION_MAC_BAD_INSTRUCTION on ppc */ |
||||
MD_EXCEPTION_CODE_MAC_PPC_INVALID_SYSCALL = 1, |
||||
/* EXC_PPC_INVALID_SYSCALL */ |
||||
MD_EXCEPTION_CODE_MAC_PPC_UNIMPLEMENTED_INSTRUCTION = 2, |
||||
/* EXC_PPC_UNIPL_INST */ |
||||
MD_EXCEPTION_CODE_MAC_PPC_PRIVILEGED_INSTRUCTION = 3, |
||||
/* EXC_PPC_PRIVINST */ |
||||
MD_EXCEPTION_CODE_MAC_PPC_PRIVILEGED_REGISTER = 4, |
||||
/* EXC_PPC_PRIVREG */ |
||||
MD_EXCEPTION_CODE_MAC_PPC_TRACE = 5, |
||||
/* EXC_PPC_TRACE */ |
||||
MD_EXCEPTION_CODE_MAC_PPC_PERFORMANCE_MONITOR = 6, |
||||
/* EXC_PPC_PERFMON */ |
||||
|
||||
/* With MD_EXCEPTION_MAC_ARITHMETIC on ppc */ |
||||
MD_EXCEPTION_CODE_MAC_PPC_OVERFLOW = 1, |
||||
/* EXC_PPC_OVERFLOW */ |
||||
MD_EXCEPTION_CODE_MAC_PPC_ZERO_DIVIDE = 2, |
||||
/* EXC_PPC_ZERO_DIVIDE */ |
||||
MD_EXCEPTION_CODE_MAC_PPC_FLOAT_INEXACT = 3, |
||||
/* EXC_FLT_INEXACT */ |
||||
MD_EXCEPTION_CODE_MAC_PPC_FLOAT_ZERO_DIVIDE = 4, |
||||
/* EXC_PPC_FLT_ZERO_DIVIDE */ |
||||
MD_EXCEPTION_CODE_MAC_PPC_FLOAT_UNDERFLOW = 5, |
||||
/* EXC_PPC_FLT_UNDERFLOW */ |
||||
MD_EXCEPTION_CODE_MAC_PPC_FLOAT_OVERFLOW = 6, |
||||
/* EXC_PPC_FLT_OVERFLOW */ |
||||
MD_EXCEPTION_CODE_MAC_PPC_FLOAT_NOT_A_NUMBER = 7, |
||||
/* EXC_PPC_FLT_NOT_A_NUMBER */ |
||||
|
||||
/* With MD_EXCEPTION_MAC_EMULATION on ppc */ |
||||
MD_EXCEPTION_CODE_MAC_PPC_NO_EMULATION = 8, |
||||
/* EXC_PPC_NOEMULATION */ |
||||
MD_EXCEPTION_CODE_MAC_PPC_ALTIVEC_ASSIST = 9, |
||||
/* EXC_PPC_ALTIVECASSIST */ |
||||
|
||||
/* With MD_EXCEPTION_MAC_SOFTWARE on ppc */ |
||||
MD_EXCEPTION_CODE_MAC_PPC_TRAP = 0x00000001, /* EXC_PPC_TRAP */ |
||||
MD_EXCEPTION_CODE_MAC_PPC_MIGRATE = 0x00010100, /* EXC_PPC_MIGRATE */ |
||||
|
||||
/* With MD_EXCEPTION_MAC_BREAKPOINT on ppc */ |
||||
MD_EXCEPTION_CODE_MAC_PPC_BREAKPOINT = 1, /* EXC_PPC_BREAKPOINT */ |
||||
|
||||
/* With MD_EXCEPTION_MAC_BAD_INSTRUCTION on x86, see also x86 interrupt
|
||||
* values below. */ |
||||
MD_EXCEPTION_CODE_MAC_X86_INVALID_OPERATION = 1, /* EXC_I386_INVOP */ |
||||
|
||||
/* With MD_EXCEPTION_MAC_ARITHMETIC on x86 */ |
||||
MD_EXCEPTION_CODE_MAC_X86_DIV = 1, /* EXC_I386_DIV */ |
||||
MD_EXCEPTION_CODE_MAC_X86_INTO = 2, /* EXC_I386_INTO */ |
||||
MD_EXCEPTION_CODE_MAC_X86_NOEXT = 3, /* EXC_I386_NOEXT */ |
||||
MD_EXCEPTION_CODE_MAC_X86_EXTOVR = 4, /* EXC_I386_EXTOVR */ |
||||
MD_EXCEPTION_CODE_MAC_X86_EXTERR = 5, /* EXC_I386_EXTERR */ |
||||
MD_EXCEPTION_CODE_MAC_X86_EMERR = 6, /* EXC_I386_EMERR */ |
||||
MD_EXCEPTION_CODE_MAC_X86_BOUND = 7, /* EXC_I386_BOUND */ |
||||
MD_EXCEPTION_CODE_MAC_X86_SSEEXTERR = 8, /* EXC_I386_SSEEXTERR */ |
||||
|
||||
/* With MD_EXCEPTION_MAC_BREAKPOINT on x86 */ |
||||
MD_EXCEPTION_CODE_MAC_X86_SGL = 1, /* EXC_I386_SGL */ |
||||
MD_EXCEPTION_CODE_MAC_X86_BPT = 2, /* EXC_I386_BPT */ |
||||
|
||||
/* With MD_EXCEPTION_MAC_BAD_INSTRUCTION on x86. These are the raw
|
||||
* x86 interrupt codes. Most of these are mapped to other Mach |
||||
* exceptions and codes, are handled, or should not occur in user space. |
||||
* A few of these will do occur with MD_EXCEPTION_MAC_BAD_INSTRUCTION. */ |
||||
/* EXC_I386_DIVERR = 0: mapped to EXC_ARITHMETIC/EXC_I386_DIV */ |
||||
/* EXC_I386_SGLSTP = 1: mapped to EXC_BREAKPOINT/EXC_I386_SGL */ |
||||
/* EXC_I386_NMIFLT = 2: should not occur in user space */ |
||||
/* EXC_I386_BPTFLT = 3: mapped to EXC_BREAKPOINT/EXC_I386_BPT */ |
||||
/* EXC_I386_INTOFLT = 4: mapped to EXC_ARITHMETIC/EXC_I386_INTO */ |
||||
/* EXC_I386_BOUNDFLT = 5: mapped to EXC_ARITHMETIC/EXC_I386_BOUND */ |
||||
/* EXC_I386_INVOPFLT = 6: mapped to EXC_BAD_INSTRUCTION/EXC_I386_INVOP */ |
||||
/* EXC_I386_NOEXTFLT = 7: should be handled by the kernel */ |
||||
/* EXC_I386_DBLFLT = 8: should be handled (if possible) by the kernel */ |
||||
/* EXC_I386_EXTOVRFLT = 9: mapped to EXC_BAD_ACCESS/(PROT_READ|PROT_EXEC) */ |
||||
MD_EXCEPTION_CODE_MAC_X86_INVALID_TASK_STATE_SEGMENT = 10, |
||||
/* EXC_INVTSSFLT */ |
||||
MD_EXCEPTION_CODE_MAC_X86_SEGMENT_NOT_PRESENT = 11, |
||||
/* EXC_SEGNPFLT */ |
||||
MD_EXCEPTION_CODE_MAC_X86_STACK_FAULT = 12, |
||||
/* EXC_STKFLT */ |
||||
MD_EXCEPTION_CODE_MAC_X86_GENERAL_PROTECTION_FAULT = 13, |
||||
/* EXC_GPFLT */ |
||||
/* EXC_I386_PGFLT = 14: should not occur in user space */ |
||||
/* EXC_I386_EXTERRFLT = 16: mapped to EXC_ARITHMETIC/EXC_I386_EXTERR */ |
||||
MD_EXCEPTION_CODE_MAC_X86_ALIGNMENT_FAULT = 17 |
||||
/* EXC_ALIGNFLT (for vector operations) */ |
||||
/* EXC_I386_ENOEXTFLT = 32: should be handled by the kernel */ |
||||
/* EXC_I386_ENDPERR = 33: should not occur */ |
||||
} MDExceptionCodeMac; |
||||
|
||||
#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_MAC_OSX_H__ */ |
@ -0,0 +1,94 @@ |
||||
/* Copyright (c) 2006, Google Inc.
|
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ |
||||
|
||||
/* minidump_exception_solaris.h: A definition of exception codes for
|
||||
* Solaris |
||||
* |
||||
* (This is C99 source, please don't corrupt it with C++.) |
||||
* |
||||
* Author: Mark Mentovai |
||||
* Split into its own file: Neal Sidhwaney */ |
||||
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_SOLARIS_H__ |
||||
#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_SOLARIS_H__ |
||||
|
||||
#include <stddef.h> |
||||
|
||||
#include "google_breakpad/common/breakpad_types.h" |
||||
|
||||
/* For (MDException).exception_code. These values come from sys/iso/signal_iso.h
|
||||
*/ |
||||
typedef enum { |
||||
MD_EXCEPTION_CODE_SOL_SIGHUP = 1, /* Hangup */ |
||||
MD_EXCEPTION_CODE_SOL_SIGINT = 2, /* interrupt (rubout) */ |
||||
MD_EXCEPTION_CODE_SOL_SIGQUIT = 3, /* quit (ASCII FS) */ |
||||
MD_EXCEPTION_CODE_SOL_SIGILL = 4, /* illegal instruction (not reset when caught) */ |
||||
MD_EXCEPTION_CODE_SOL_SIGTRAP = 5, /* trace trap (not reset when caught) */ |
||||
MD_EXCEPTION_CODE_SOL_SIGIOT = 6, /* IOT instruction */ |
||||
MD_EXCEPTION_CODE_SOL_SIGABRT = 6, /* used by abort, replace SIGIOT in the future */ |
||||
MD_EXCEPTION_CODE_SOL_SIGEMT = 7, /* EMT instruction */ |
||||
MD_EXCEPTION_CODE_SOL_SIGFPE = 8, /* floating point exception */ |
||||
MD_EXCEPTION_CODE_SOL_SIGKILL = 9, /* kill (cannot be caught or ignored) */ |
||||
MD_EXCEPTION_CODE_SOL_SIGBUS = 10, /* bus error */ |
||||
MD_EXCEPTION_CODE_SOL_SIGSEGV = 11, /* segmentation violation */ |
||||
MD_EXCEPTION_CODE_SOL_SIGSYS = 12, /* bad argument to system call */ |
||||
MD_EXCEPTION_CODE_SOL_SIGPIPE = 13, /* write on a pipe with no one to read it */ |
||||
MD_EXCEPTION_CODE_SOL_SIGALRM = 14, /* alarm clock */ |
||||
MD_EXCEPTION_CODE_SOL_SIGTERM = 15, /* software termination signal from kill */ |
||||
MD_EXCEPTION_CODE_SOL_SIGUSR1 = 16, /* user defined signal 1 */ |
||||
MD_EXCEPTION_CODE_SOL_SIGUSR2 = 17, /* user defined signal 2 */ |
||||
MD_EXCEPTION_CODE_SOL_SIGCLD = 18, /* child status change */ |
||||
MD_EXCEPTION_CODE_SOL_SIGCHLD = 18, /* child status change alias (POSIX) */ |
||||
MD_EXCEPTION_CODE_SOL_SIGPWR = 19, /* power-fail restart */ |
||||
MD_EXCEPTION_CODE_SOL_SIGWINCH = 20, /* window size change */ |
||||
MD_EXCEPTION_CODE_SOL_SIGURG = 21, /* urgent socket condition */ |
||||
MD_EXCEPTION_CODE_SOL_SIGPOLL = 22, /* pollable event occured */ |
||||
MD_EXCEPTION_CODE_SOL_SIGIO = 22, /* socket I/O possible (SIGPOLL alias) */ |
||||
MD_EXCEPTION_CODE_SOL_SIGSTOP = 23, /* stop (cannot be caught or ignored) */ |
||||
MD_EXCEPTION_CODE_SOL_SIGTSTP = 24, /* user stop requested from tty */ |
||||
MD_EXCEPTION_CODE_SOL_SIGCONT = 25, /* stopped process has been continued */ |
||||
MD_EXCEPTION_CODE_SOL_SIGTTIN = 26, /* background tty read attempted */ |
||||
MD_EXCEPTION_CODE_SOL_SIGTTOU = 27, /* background tty write attempted */ |
||||
MD_EXCEPTION_CODE_SOL_SIGVTALRM = 28, /* virtual timer expired */ |
||||
MD_EXCEPTION_CODE_SOL_SIGPROF = 29, /* profiling timer expired */ |
||||
MD_EXCEPTION_CODE_SOL_SIGXCPU = 30, /* exceeded cpu limit */ |
||||
MD_EXCEPTION_CODE_SOL_SIGXFSZ = 31, /* exceeded file size limit */ |
||||
MD_EXCEPTION_CODE_SOL_SIGWAITING = 32, /* reserved signal no longer used by threading code */ |
||||
MD_EXCEPTION_CODE_SOL_SIGLWP = 33, /* reserved signal no longer used by threading code */ |
||||
MD_EXCEPTION_CODE_SOL_SIGFREEZE = 34, /* special signal used by CPR */ |
||||
MD_EXCEPTION_CODE_SOL_SIGTHAW = 35, /* special signal used by CPR */ |
||||
MD_EXCEPTION_CODE_SOL_SIGCANCEL = 36, /* reserved signal for thread cancellation */ |
||||
MD_EXCEPTION_CODE_SOL_SIGLOST = 37, /* resource lost (eg, record-lock lost) */ |
||||
MD_EXCEPTION_CODE_SOL_SIGXRES = 38, /* resource control exceeded */ |
||||
MD_EXCEPTION_CODE_SOL_SIGJVM1 = 39, /* reserved signal for Java Virtual Machine */ |
||||
MD_EXCEPTION_CODE_SOL_SIGJVM2 = 40 /* reserved signal for Java Virtual Machine */ |
||||
} MDExceptionCodeSolaris; |
||||
|
||||
#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_SOLARIS_H__ */ |
@ -0,0 +1,102 @@ |
||||
/* Copyright (c) 2006, Google Inc.
|
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ |
||||
|
||||
/* minidump_exception_win32.h: Definitions of exception codes for
|
||||
* Win32 platform |
||||
* |
||||
* (This is C99 source, please don't corrupt it with C++.) |
||||
* |
||||
* Author: Mark Mentovai |
||||
* Split into its own file: Neal Sidhwaney */ |
||||
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_WIN32_H__ |
||||
#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_WIN32_H__ |
||||
|
||||
#include <stddef.h> |
||||
|
||||
#include "google_breakpad/common/breakpad_types.h" |
||||
|
||||
|
||||
/* For (MDException).exception_code. These values come from WinBase.h
|
||||
* and WinNT.h (names beginning with EXCEPTION_ are in WinBase.h, |
||||
* they are STATUS_ in WinNT.h). */ |
||||
typedef enum { |
||||
MD_EXCEPTION_CODE_WIN_CONTROL_C = 0x40010005, |
||||
/* DBG_CONTROL_C */ |
||||
MD_EXCEPTION_CODE_WIN_GUARD_PAGE_VIOLATION = 0x80000001, |
||||
/* EXCEPTION_GUARD_PAGE */ |
||||
MD_EXCEPTION_CODE_WIN_DATATYPE_MISALIGNMENT = 0x80000002, |
||||
/* EXCEPTION_DATATYPE_MISALIGNMENT */ |
||||
MD_EXCEPTION_CODE_WIN_BREAKPOINT = 0x80000003, |
||||
/* EXCEPTION_BREAKPOINT */ |
||||
MD_EXCEPTION_CODE_WIN_SINGLE_STEP = 0x80000004, |
||||
/* EXCEPTION_SINGLE_STEP */ |
||||
MD_EXCEPTION_CODE_WIN_ACCESS_VIOLATION = 0xc0000005, |
||||
/* EXCEPTION_ACCESS_VIOLATION */ |
||||
MD_EXCEPTION_CODE_WIN_IN_PAGE_ERROR = 0xc0000006, |
||||
/* EXCEPTION_IN_PAGE_ERROR */ |
||||
MD_EXCEPTION_CODE_WIN_INVALID_HANDLE = 0xc0000008, |
||||
/* EXCEPTION_INVALID_HANDLE */ |
||||
MD_EXCEPTION_CODE_WIN_ILLEGAL_INSTRUCTION = 0xc000001d, |
||||
/* EXCEPTION_ILLEGAL_INSTRUCTION */ |
||||
MD_EXCEPTION_CODE_WIN_NONCONTINUABLE_EXCEPTION = 0xc0000025, |
||||
/* EXCEPTION_NONCONTINUABLE_EXCEPTION */ |
||||
MD_EXCEPTION_CODE_WIN_INVALID_DISPOSITION = 0xc0000026, |
||||
/* EXCEPTION_INVALID_DISPOSITION */ |
||||
MD_EXCEPTION_CODE_WIN_ARRAY_BOUNDS_EXCEEDED = 0xc000008c, |
||||
/* EXCEPTION_BOUNDS_EXCEEDED */ |
||||
MD_EXCEPTION_CODE_WIN_FLOAT_DENORMAL_OPERAND = 0xc000008d, |
||||
/* EXCEPTION_FLT_DENORMAL_OPERAND */ |
||||
MD_EXCEPTION_CODE_WIN_FLOAT_DIVIDE_BY_ZERO = 0xc000008e, |
||||
/* EXCEPTION_FLT_DIVIDE_BY_ZERO */ |
||||
MD_EXCEPTION_CODE_WIN_FLOAT_INEXACT_RESULT = 0xc000008f, |
||||
/* EXCEPTION_FLT_INEXACT_RESULT */ |
||||
MD_EXCEPTION_CODE_WIN_FLOAT_INVALID_OPERATION = 0xc0000090, |
||||
/* EXCEPTION_FLT_INVALID_OPERATION */ |
||||
MD_EXCEPTION_CODE_WIN_FLOAT_OVERFLOW = 0xc0000091, |
||||
/* EXCEPTION_FLT_OVERFLOW */ |
||||
MD_EXCEPTION_CODE_WIN_FLOAT_STACK_CHECK = 0xc0000092, |
||||
/* EXCEPTION_FLT_STACK_CHECK */ |
||||
MD_EXCEPTION_CODE_WIN_FLOAT_UNDERFLOW = 0xc0000093, |
||||
/* EXCEPTION_FLT_UNDERFLOW */ |
||||
MD_EXCEPTION_CODE_WIN_INTEGER_DIVIDE_BY_ZERO = 0xc0000094, |
||||
/* EXCEPTION_INT_DIVIDE_BY_ZERO */ |
||||
MD_EXCEPTION_CODE_WIN_INTEGER_OVERFLOW = 0xc0000095, |
||||
/* EXCEPTION_INT_OVERFLOW */ |
||||
MD_EXCEPTION_CODE_WIN_PRIVILEGED_INSTRUCTION = 0xc0000096, |
||||
/* EXCEPTION_PRIV_INSTRUCTION */ |
||||
MD_EXCEPTION_CODE_WIN_STACK_OVERFLOW = 0xc00000fd, |
||||
/* EXCEPTION_STACK_OVERFLOW */ |
||||
MD_EXCEPTION_CODE_WIN_POSSIBLE_DEADLOCK = 0xc0000194 |
||||
/* EXCEPTION_POSSIBLE_DEADLOCK */ |
||||
} MDExceptionCodeWin; |
||||
|
||||
|
||||
#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_WIN32_H__ */ |
@ -0,0 +1,721 @@ |
||||
/* Copyright (c) 2006, Google Inc.
|
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ |
||||
|
||||
/* minidump_format.h: A cross-platform reimplementation of minidump-related
|
||||
* portions of DbgHelp.h from the Windows Platform SDK. |
||||
* |
||||
* (This is C99 source, please don't corrupt it with C++.) |
||||
* |
||||
* Structures that are defined by Microsoft to contain a zero-length array |
||||
* are instead defined here to contain an array with one element, as |
||||
* zero-length arrays are forbidden by standard C and C++. In these cases, |
||||
* *_minsize constants are provided to be used in place of sizeof. For a |
||||
* cleaner interface to these sizes when using C++, see minidump_size.h. |
||||
* |
||||
* These structures are also sufficient to populate minidump files. |
||||
* |
||||
* These definitions may be extended to support handling minidump files |
||||
* for other CPUs and other operating systems. |
||||
* |
||||
* Because precise data type sizes are crucial for this implementation to |
||||
* function properly and portably in terms of interoperability with minidumps |
||||
* produced by DbgHelp on Windows, a set of primitive types with known sizes |
||||
* are used as the basis of each structure defined by this file. DbgHelp |
||||
* on Windows is assumed to be the reference implementation; this file |
||||
* seeks to provide a cross-platform compatible implementation. To avoid |
||||
* collisions with the types and values defined and used by DbgHelp in the |
||||
* event that this implementation is used on Windows, each type and value |
||||
* defined here is given a new name, beginning with "MD". Names of the |
||||
* equivalent types and values in the Windows Platform SDK are given in |
||||
* comments. |
||||
* |
||||
* Author: Mark Mentovai */ |
||||
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_FORMAT_H__ |
||||
#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_FORMAT_H__ |
||||
|
||||
#include <stddef.h> |
||||
|
||||
#include "google_breakpad/common/breakpad_types.h" |
||||
|
||||
|
||||
#if defined(_MSC_VER) |
||||
/* Disable "zero-sized array in struct/union" warnings when compiling in
|
||||
* MSVC. DbgHelp.h does this too. */ |
||||
#pragma warning(push) |
||||
#pragma warning(disable:4200) |
||||
#endif /* _MSC_VER */ |
||||
|
||||
|
||||
/*
|
||||
* guiddef.h |
||||
*/ |
||||
|
||||
typedef struct { |
||||
u_int32_t data1; |
||||
u_int16_t data2; |
||||
u_int16_t data3; |
||||
u_int8_t data4[8]; |
||||
} MDGUID; /* GUID */ |
||||
|
||||
|
||||
/*
|
||||
* WinNT.h |
||||
*/ |
||||
|
||||
/* Non-x86 CPU identifiers found in the high 26 bits of
|
||||
* (MDRawContext*).context_flags. These aren't used by Breakpad, but are |
||||
* defined here for reference, to avoid assigning values that conflict |
||||
* (although some values already conflict). */ |
||||
#define MD_CONTEXT_IA64 0x00080000 /* CONTEXT_IA64 */ |
||||
#define MD_CONTEXT_AMD64 0x00100000 /* CONTEXT_AMD64 */ |
||||
/* Additional values from winnt.h in the Windows CE 5.0 SDK: */ |
||||
#define MD_CONTEXT_SHX 0x000000c0 /* CONTEXT_SH4 (Super-H, includes SH3) */ |
||||
#define MD_CONTEXT_ARM 0x00000040 /* CONTEXT_ARM (0x40 bit set in SHx?) */ |
||||
#define MD_CONTEXT_MIPS 0x00010000 /* CONTEXT_R4000 (same value as x86?) */ |
||||
#define MD_CONTEXT_ALPHA 0x00020000 /* CONTEXT_ALPHA */ |
||||
|
||||
#define MD_CONTEXT_CPU_MASK 0xffffffc0 |
||||
|
||||
|
||||
/* This is a base type for MDRawContextX86 and MDRawContextPPC. This
|
||||
* structure should never be allocated directly. The actual structure type |
||||
* can be determined by examining the context_flags field. */ |
||||
typedef struct { |
||||
u_int32_t context_flags; |
||||
} MDRawContextBase; |
||||
|
||||
#include "minidump_cpu_sparc.h" |
||||
#include "minidump_cpu_x86.h" |
||||
#include "minidump_cpu_ppc.h" |
||||
#include "minidump_cpu_ppc64.h" |
||||
#include "minidump_cpu_amd64.h" |
||||
|
||||
|
||||
/*
|
||||
* WinVer.h |
||||
*/ |
||||
|
||||
|
||||
typedef struct { |
||||
u_int32_t signature; |
||||
u_int32_t struct_version; |
||||
u_int32_t file_version_hi; |
||||
u_int32_t file_version_lo; |
||||
u_int32_t product_version_hi; |
||||
u_int32_t product_version_lo; |
||||
u_int32_t file_flags_mask; /* Identifies valid bits in fileFlags */ |
||||
u_int32_t file_flags; |
||||
u_int32_t file_os; |
||||
u_int32_t file_type; |
||||
u_int32_t file_subtype; |
||||
u_int32_t file_date_hi; |
||||
u_int32_t file_date_lo; |
||||
} MDVSFixedFileInfo; /* VS_FIXEDFILEINFO */ |
||||
|
||||
/* For (MDVSFixedFileInfo).signature */ |
||||
#define MD_VSFIXEDFILEINFO_SIGNATURE 0xfeef04bd |
||||
/* VS_FFI_SIGNATURE */ |
||||
|
||||
/* For (MDVSFixedFileInfo).version */ |
||||
#define MD_VSFIXEDFILEINFO_VERSION 0x00010000 |
||||
/* VS_FFI_STRUCVERSION */ |
||||
|
||||
/* For (MDVSFixedFileInfo).file_flags_mask and
|
||||
* (MDVSFixedFileInfo).file_flags */ |
||||
#define MD_VSFIXEDFILEINFO_FILE_FLAGS_DEBUG 0x00000001 |
||||
/* VS_FF_DEBUG */ |
||||
#define MD_VSFIXEDFILEINFO_FILE_FLAGS_PRERELEASE 0x00000002 |
||||
/* VS_FF_PRERELEASE */ |
||||
#define MD_VSFIXEDFILEINFO_FILE_FLAGS_PATCHED 0x00000004 |
||||
/* VS_FF_PATCHED */ |
||||
#define MD_VSFIXEDFILEINFO_FILE_FLAGS_PRIVATEBUILD 0x00000008 |
||||
/* VS_FF_PRIVATEBUILD */ |
||||
#define MD_VSFIXEDFILEINFO_FILE_FLAGS_INFOINFERRED 0x00000010 |
||||
/* VS_FF_INFOINFERRED */ |
||||
#define MD_VSFIXEDFILEINFO_FILE_FLAGS_SPECIALBUILD 0x00000020 |
||||
/* VS_FF_SPECIALBUILD */ |
||||
|
||||
/* For (MDVSFixedFileInfo).file_os: high 16 bits */ |
||||
#define MD_VSFIXEDFILEINFO_FILE_OS_UNKNOWN 0 /* VOS_UNKNOWN */ |
||||
#define MD_VSFIXEDFILEINFO_FILE_OS_DOS (1 << 16) /* VOS_DOS */ |
||||
#define MD_VSFIXEDFILEINFO_FILE_OS_OS216 (2 << 16) /* VOS_OS216 */ |
||||
#define MD_VSFIXEDFILEINFO_FILE_OS_OS232 (3 << 16) /* VOS_OS232 */ |
||||
#define MD_VSFIXEDFILEINFO_FILE_OS_NT (4 << 16) /* VOS_NT */ |
||||
#define MD_VSFIXEDFILEINFO_FILE_OS_WINCE (5 << 16) /* VOS_WINCE */ |
||||
/* Low 16 bits */ |
||||
#define MD_VSFIXEDFILEINFO_FILE_OS__BASE 0 /* VOS__BASE */ |
||||
#define MD_VSFIXEDFILEINFO_FILE_OS__WINDOWS16 1 /* VOS__WINDOWS16 */ |
||||
#define MD_VSFIXEDFILEINFO_FILE_OS__PM16 2 /* VOS__PM16 */ |
||||
#define MD_VSFIXEDFILEINFO_FILE_OS__PM32 3 /* VOS__PM32 */ |
||||
#define MD_VSFIXEDFILEINFO_FILE_OS__WINDOWS32 4 /* VOS__WINDOWS32 */ |
||||
|
||||
/* For (MDVSFixedFileInfo).file_type */ |
||||
#define MD_VSFIXEDFILEINFO_FILE_TYPE_UNKNOWN 0 /* VFT_UNKNOWN */ |
||||
#define MD_VSFIXEDFILEINFO_FILE_TYPE_APP 1 /* VFT_APP */ |
||||
#define MD_VSFIXEDFILEINFO_FILE_TYPE_DLL 2 /* VFT_DLL */ |
||||
#define MD_VSFIXEDFILEINFO_FILE_TYPE_DRV 3 /* VFT_DLL */ |
||||
#define MD_VSFIXEDFILEINFO_FILE_TYPE_FONT 4 /* VFT_FONT */ |
||||
#define MD_VSFIXEDFILEINFO_FILE_TYPE_VXD 5 /* VFT_VXD */ |
||||
#define MD_VSFIXEDFILEINFO_FILE_TYPE_STATIC_LIB 7 /* VFT_STATIC_LIB */ |
||||
|
||||
/* For (MDVSFixedFileInfo).file_subtype */ |
||||
#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_UNKNOWN 0 |
||||
/* VFT2_UNKNOWN */ |
||||
/* with file_type = MD_VSFIXEDFILEINFO_FILETYPE_DRV */ |
||||
#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_PRINTER 1 |
||||
/* VFT2_DRV_PRINTER */ |
||||
#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_KEYBOARD 2 |
||||
/* VFT2_DRV_KEYBOARD */ |
||||
#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_LANGUAGE 3 |
||||
/* VFT2_DRV_LANGUAGE */ |
||||
#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_DISPLAY 4 |
||||
/* VFT2_DRV_DISPLAY */ |
||||
#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_MOUSE 5 |
||||
/* VFT2_DRV_MOUSE */ |
||||
#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_NETWORK 6 |
||||
/* VFT2_DRV_NETWORK */ |
||||
#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_SYSTEM 7 |
||||
/* VFT2_DRV_SYSTEM */ |
||||
#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_INSTALLABLE 8 |
||||
/* VFT2_DRV_INSTALLABLE */ |
||||
#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_SOUND 9 |
||||
/* VFT2_DRV_SOUND */ |
||||
#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_COMM 10 |
||||
/* VFT2_DRV_COMM */ |
||||
#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_INPUTMETHOD 11 |
||||
/* VFT2_DRV_INPUTMETHOD */ |
||||
#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_VERSIONED_PRINTER 12 |
||||
/* VFT2_DRV_VERSIONED_PRINTER */ |
||||
/* with file_type = MD_VSFIXEDFILEINFO_FILETYPE_FONT */ |
||||
#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_FONT_RASTER 1 |
||||
/* VFT2_FONT_RASTER */ |
||||
#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_FONT_VECTOR 2 |
||||
/* VFT2_FONT_VECTOR */ |
||||
#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_FONT_TRUETYPE 3 |
||||
/* VFT2_FONT_TRUETYPE */ |
||||
|
||||
|
||||
/*
|
||||
* DbgHelp.h |
||||
*/ |
||||
|
||||
|
||||
/* An MDRVA is an offset into the minidump file. The beginning of the
|
||||
* MDRawHeader is at offset 0. */ |
||||
typedef u_int32_t MDRVA; /* RVA */ |
||||
|
||||
typedef struct { |
||||
u_int32_t data_size; |
||||
MDRVA rva; |
||||
} MDLocationDescriptor; /* MINIDUMP_LOCATION_DESCRIPTOR */ |
||||
|
||||
|
||||
typedef struct { |
||||
/* The base address of the memory range on the host that produced the
|
||||
* minidump. */ |
||||
u_int64_t start_of_memory_range; |
||||
|
||||
MDLocationDescriptor memory; |
||||
} MDMemoryDescriptor; /* MINIDUMP_MEMORY_DESCRIPTOR */ |
||||
|
||||
|
||||
typedef struct { |
||||
u_int32_t signature; |
||||
u_int32_t version; |
||||
u_int32_t stream_count; |
||||
MDRVA stream_directory_rva; /* A |stream_count|-sized array of
|
||||
* MDRawDirectory structures. */ |
||||
u_int32_t checksum; /* Can be 0. In fact, that's all that's
|
||||
* been found in minidump files. */ |
||||
u_int32_t time_date_stamp; /* time_t */ |
||||
u_int64_t flags; |
||||
} MDRawHeader; /* MINIDUMP_HEADER */ |
||||
|
||||
/* For (MDRawHeader).signature and (MDRawHeader).version. Note that only the
|
||||
* low 16 bits of (MDRawHeader).version are MD_HEADER_VERSION. Per the |
||||
* documentation, the high 16 bits are implementation-specific. */ |
||||
#define MD_HEADER_SIGNATURE 0x504d444d /* 'PMDM' */ |
||||
/* MINIDUMP_SIGNATURE */ |
||||
#define MD_HEADER_VERSION 0x0000a793 /* 42899 */ |
||||
/* MINIDUMP_VERSION */ |
||||
|
||||
/* For (MDRawHeader).flags: */ |
||||
typedef enum { |
||||
/* MD_NORMAL is the standard type of minidump. It includes full
|
||||
* streams for the thread list, module list, exception, system info, |
||||
* and miscellaneous info. A memory list stream is also present, |
||||
* pointing to the same stack memory contained in the thread list, |
||||
* as well as a 256-byte region around the instruction address that |
||||
* was executing when the exception occurred. Stack memory is from |
||||
* 4 bytes below a thread's stack pointer up to the top of the |
||||
* memory region encompassing the stack. */ |
||||
MD_NORMAL = 0x00000000, |
||||
MD_WITH_DATA_SEGS = 0x00000001, |
||||
MD_WITH_FULL_MEMORY = 0x00000002, |
||||
MD_WITH_HANDLE_DATA = 0x00000004, |
||||
MD_FILTER_MEMORY = 0x00000008, |
||||
MD_SCAN_MEMORY = 0x00000010, |
||||
MD_WITH_UNLOADED_MODULES = 0x00000020, |
||||
MD_WITH_INDIRECTLY_REFERENCED_MEMORY = 0x00000040, |
||||
MD_FILTER_MODULE_PATHS = 0x00000080, |
||||
MD_WITH_PROCESS_THREAD_DATA = 0x00000100, |
||||
MD_WITH_PRIVATE_READ_WRITE_MEMORY = 0x00000200, |
||||
MD_WITHOUT_OPTIONAL_DATA = 0x00000400, |
||||
MD_WITH_FULL_MEMORY_INFO = 0x00000800, |
||||
MD_WITH_THREAD_INFO = 0x00001000, |
||||
MD_WITH_CODE_SEGS = 0x00002000 |
||||
} MDType; /* MINIDUMP_TYPE */ |
||||
|
||||
|
||||
typedef struct { |
||||
u_int32_t stream_type; |
||||
MDLocationDescriptor location; |
||||
} MDRawDirectory; /* MINIDUMP_DIRECTORY */ |
||||
|
||||
/* For (MDRawDirectory).stream_type */ |
||||
typedef enum { |
||||
MD_UNUSED_STREAM = 0, |
||||
MD_RESERVED_STREAM_0 = 1, |
||||
MD_RESERVED_STREAM_1 = 2, |
||||
MD_THREAD_LIST_STREAM = 3, /* MDRawThreadList */ |
||||
MD_MODULE_LIST_STREAM = 4, /* MDRawModuleList */ |
||||
MD_MEMORY_LIST_STREAM = 5, /* MDRawMemoryList */ |
||||
MD_EXCEPTION_STREAM = 6, /* MDRawExceptionStream */ |
||||
MD_SYSTEM_INFO_STREAM = 7, /* MDRawSystemInfo */ |
||||
MD_THREAD_EX_LIST_STREAM = 8, |
||||
MD_MEMORY_64_LIST_STREAM = 9, |
||||
MD_COMMENT_STREAM_A = 10, |
||||
MD_COMMENT_STREAM_W = 11, |
||||
MD_HANDLE_DATA_STREAM = 12, |
||||
MD_FUNCTION_TABLE_STREAM = 13, |
||||
MD_UNLOADED_MODULE_LIST_STREAM = 14, |
||||
MD_MISC_INFO_STREAM = 15, /* MDRawMiscInfo */ |
||||
MD_LAST_RESERVED_STREAM = 0x0000ffff, |
||||
|
||||
/* Breakpad extension types. 0x4767 = "Gg" */ |
||||
MD_BREAKPAD_INFO_STREAM = 0x47670001, /* MDRawBreakpadInfo */ |
||||
MD_ASSERTION_INFO_STREAM = 0x47670002 /* MDRawAssertionInfo */ |
||||
} MDStreamType; /* MINIDUMP_STREAM_TYPE */ |
||||
|
||||
|
||||
typedef struct { |
||||
u_int32_t length; /* Length of buffer in bytes (not characters),
|
||||
* excluding 0-terminator */ |
||||
u_int16_t buffer[1]; /* UTF-16-encoded, 0-terminated */ |
||||
} MDString; /* MINIDUMP_STRING */ |
||||
|
||||
static const size_t MDString_minsize = offsetof(MDString, buffer[0]); |
||||
|
||||
|
||||
typedef struct { |
||||
u_int32_t thread_id; |
||||
u_int32_t suspend_count; |
||||
u_int32_t priority_class; |
||||
u_int32_t priority; |
||||
u_int64_t teb; /* Thread environment block */ |
||||
MDMemoryDescriptor stack; |
||||
MDLocationDescriptor thread_context; /* MDRawContext[CPU] */ |
||||
} MDRawThread; /* MINIDUMP_THREAD */ |
||||
|
||||
|
||||
typedef struct { |
||||
u_int32_t number_of_threads; |
||||
MDRawThread threads[1]; |
||||
} MDRawThreadList; /* MINIDUMP_THREAD_LIST */ |
||||
|
||||
static const size_t MDRawThreadList_minsize = offsetof(MDRawThreadList, |
||||
threads[0]); |
||||
|
||||
|
||||
typedef struct { |
||||
u_int64_t base_of_image; |
||||
u_int32_t size_of_image; |
||||
u_int32_t checksum; /* 0 if unknown */ |
||||
u_int32_t time_date_stamp; /* time_t */ |
||||
MDRVA module_name_rva; /* MDString, pathname or filename */ |
||||
MDVSFixedFileInfo version_info; |
||||
|
||||
/* The next field stores a CodeView record and is populated when a module's
|
||||
* debug information resides in a PDB file. It identifies the PDB file. */ |
||||
MDLocationDescriptor cv_record; |
||||
|
||||
/* The next field is populated when a module's debug information resides
|
||||
* in a DBG file. It identifies the DBG file. This field is effectively |
||||
* obsolete with modules built by recent toolchains. */ |
||||
MDLocationDescriptor misc_record; |
||||
|
||||
/* Alignment problem: reserved0 and reserved1 are defined by the platform
|
||||
* SDK as 64-bit quantities. However, that results in a structure whose |
||||
* alignment is unpredictable on different CPUs and ABIs. If the ABI |
||||
* specifies full alignment of 64-bit quantities in structures (as ppc |
||||
* does), there will be padding between miscRecord and reserved0. If |
||||
* 64-bit quantities can be aligned on 32-bit boundaries (as on x86), |
||||
* this padding will not exist. (Note that the structure up to this point |
||||
* contains 1 64-bit member followed by 21 32-bit members.) |
||||
* As a workaround, reserved0 and reserved1 are instead defined here as |
||||
* four 32-bit quantities. This should be harmless, as there are |
||||
* currently no known uses for these fields. */ |
||||
u_int32_t reserved0[2]; |
||||
u_int32_t reserved1[2]; |
||||
} MDRawModule; /* MINIDUMP_MODULE */ |
||||
|
||||
/* The inclusion of a 64-bit type in MINIDUMP_MODULE forces the struct to
|
||||
* be tail-padded out to a multiple of 64 bits under some ABIs (such as PPC). |
||||
* This doesn't occur on systems that don't tail-pad in this manner. Define |
||||
* this macro to be the usable size of the MDRawModule struct, and use it in |
||||
* place of sizeof(MDRawModule). */ |
||||
#define MD_MODULE_SIZE 108 |
||||
|
||||
|
||||
/* (MDRawModule).cv_record can reference MDCVInfoPDB20 or MDCVInfoPDB70.
|
||||
* Ref.: http://www.debuginfo.com/articles/debuginfomatch.html
|
||||
* MDCVInfoPDB70 is the expected structure type with recent toolchains. */ |
||||
|
||||
typedef struct { |
||||
u_int32_t signature; |
||||
u_int32_t offset; /* Offset to debug data (expect 0 in minidump) */ |
||||
} MDCVHeader; |
||||
|
||||
typedef struct { |
||||
MDCVHeader cv_header; |
||||
u_int32_t signature; /* time_t debug information created */ |
||||
u_int32_t age; /* revision of PDB file */ |
||||
u_int8_t pdb_file_name[1]; /* Pathname or filename of PDB file */ |
||||
} MDCVInfoPDB20; |
||||
|
||||
static const size_t MDCVInfoPDB20_minsize = offsetof(MDCVInfoPDB20, |
||||
pdb_file_name[0]); |
||||
|
||||
#define MD_CVINFOPDB20_SIGNATURE 0x3031424e /* cvHeader.signature = '01BN' */ |
||||
|
||||
typedef struct { |
||||
u_int32_t cv_signature; |
||||
MDGUID signature; /* GUID, identifies PDB file */ |
||||
u_int32_t age; /* Identifies incremental changes to PDB file */ |
||||
u_int8_t pdb_file_name[1]; /* Pathname or filename of PDB file,
|
||||
* 0-terminated 8-bit character data (UTF-8?) */ |
||||
} MDCVInfoPDB70; |
||||
|
||||
static const size_t MDCVInfoPDB70_minsize = offsetof(MDCVInfoPDB70, |
||||
pdb_file_name[0]); |
||||
|
||||
#define MD_CVINFOPDB70_SIGNATURE 0x53445352 /* cvSignature = 'SDSR' */ |
||||
|
||||
typedef struct { |
||||
u_int32_t data1[2]; |
||||
u_int32_t data2; |
||||
u_int32_t data3; |
||||
u_int32_t data4; |
||||
u_int32_t data5[3]; |
||||
u_int8_t extra[2]; |
||||
} MDCVInfoELF; |
||||
|
||||
/* In addition to the two CodeView record formats above, used for linking
|
||||
* to external pdb files, it is possible for debugging data to be carried |
||||
* directly in the CodeView record itself. These signature values will |
||||
* be found in the first 4 bytes of the CodeView record. Additional values |
||||
* not commonly experienced in the wild are given by "Microsoft Symbol and |
||||
* Type Information", http://www.x86.org/ftp/manuals/tools/sym.pdf, section |
||||
* 7.2. An in-depth description of the CodeView 4.1 format is given by |
||||
* "Undocumented Windows 2000 Secrets", Windows 2000 Debugging Support/ |
||||
* Microsoft Symbol File Internals/CodeView Subsections, |
||||
* http://www.rawol.com/features/undocumented/sbs-w2k-1-windows-2000-debugging-support.pdf
|
||||
*/ |
||||
#define MD_CVINFOCV41_SIGNATURE 0x3930424e /* '90BN', CodeView 4.10. */ |
||||
#define MD_CVINFOCV50_SIGNATURE 0x3131424e /* '11BN', CodeView 5.0, |
||||
* MS C7-format (/Z7). */ |
||||
|
||||
#define MD_CVINFOUNKNOWN_SIGNATURE 0xffffffff /* An unlikely value. */ |
||||
|
||||
/* (MDRawModule).miscRecord can reference MDImageDebugMisc. The Windows
|
||||
* structure is actually defined in WinNT.h. This structure is effectively |
||||
* obsolete with modules built by recent toolchains. */ |
||||
|
||||
typedef struct { |
||||
u_int32_t data_type; /* IMAGE_DEBUG_TYPE_*, not defined here because
|
||||
* this debug record type is mostly obsolete. */ |
||||
u_int32_t length; /* Length of entire MDImageDebugMisc structure */ |
||||
u_int8_t unicode; /* True if data is multibyte */ |
||||
u_int8_t reserved[3]; |
||||
u_int8_t data[1]; |
||||
} MDImageDebugMisc; /* IMAGE_DEBUG_MISC */ |
||||
|
||||
static const size_t MDImageDebugMisc_minsize = offsetof(MDImageDebugMisc, |
||||
data[0]); |
||||
|
||||
|
||||
typedef struct { |
||||
u_int32_t number_of_modules; |
||||
MDRawModule modules[1]; |
||||
} MDRawModuleList; /* MINIDUMP_MODULE_LIST */ |
||||
|
||||
static const size_t MDRawModuleList_minsize = offsetof(MDRawModuleList, |
||||
modules[0]); |
||||
|
||||
|
||||
typedef struct { |
||||
u_int32_t number_of_memory_ranges; |
||||
MDMemoryDescriptor memory_ranges[1]; |
||||
} MDRawMemoryList; /* MINIDUMP_MEMORY_LIST */ |
||||
|
||||
static const size_t MDRawMemoryList_minsize = offsetof(MDRawMemoryList, |
||||
memory_ranges[0]); |
||||
|
||||
|
||||
#define MD_EXCEPTION_MAXIMUM_PARAMETERS 15 |
||||
|
||||
typedef struct { |
||||
u_int32_t exception_code; /* Windows: MDExceptionCodeWin,
|
||||
* Mac OS X: MDExceptionMac, |
||||
* Linux: MDExceptionCodeLinux. */ |
||||
u_int32_t exception_flags; /* Windows: 1 if noncontinuable,
|
||||
Mac OS X: MDExceptionCodeMac. */ |
||||
u_int64_t exception_record; /* Address (in the minidump-producing host's
|
||||
* memory) of another MDException, for |
||||
* nested exceptions. */ |
||||
u_int64_t exception_address; /* The address that caused the exception.
|
||||
* Mac OS X: exception subcode (which is |
||||
* typically the address). */ |
||||
u_int32_t number_parameters; /* Number of valid elements in
|
||||
* exception_information. */ |
||||
u_int32_t __align; |
||||
u_int64_t exception_information[MD_EXCEPTION_MAXIMUM_PARAMETERS]; |
||||
} MDException; /* MINIDUMP_EXCEPTION */ |
||||
|
||||
#include "minidump_exception_win32.h" |
||||
#include "minidump_exception_mac.h" |
||||
#include "minidump_exception_linux.h" |
||||
#include "minidump_exception_solaris.h" |
||||
|
||||
typedef struct { |
||||
u_int32_t thread_id; /* Thread in which the exception
|
||||
* occurred. Corresponds to |
||||
* (MDRawThread).thread_id. */ |
||||
u_int32_t __align; |
||||
MDException exception_record; |
||||
MDLocationDescriptor thread_context; /* MDRawContext[CPU] */ |
||||
} MDRawExceptionStream; /* MINIDUMP_EXCEPTION_STREAM */ |
||||
|
||||
|
||||
typedef union { |
||||
struct { |
||||
u_int32_t vendor_id[3]; /* cpuid 0: ebx, edx, ecx */ |
||||
u_int32_t version_information; /* cpuid 1: eax */ |
||||
u_int32_t feature_information; /* cpuid 1: edx */ |
||||
u_int32_t amd_extended_cpu_features; /* cpuid 0x80000001, ebx */ |
||||
} x86_cpu_info; |
||||
struct { |
||||
u_int64_t processor_features[2]; |
||||
} other_cpu_info; |
||||
} MDCPUInformation; /* CPU_INFORMATION */ |
||||
|
||||
|
||||
typedef struct { |
||||
/* The next 3 fields and numberOfProcessors are from the SYSTEM_INFO
|
||||
* structure as returned by GetSystemInfo */ |
||||
u_int16_t processor_architecture; |
||||
u_int16_t processor_level; /* x86: 5 = 586, 6 = 686, ... */ |
||||
u_int16_t processor_revision; /* x86: 0xMMSS, where MM=model,
|
||||
* SS=stepping */ |
||||
|
||||
u_int8_t number_of_processors; |
||||
u_int8_t product_type; /* Windows: VER_NT_* from WinNT.h */ |
||||
|
||||
/* The next 5 fields are from the OSVERSIONINFO structure as returned
|
||||
* by GetVersionEx */ |
||||
u_int32_t major_version; |
||||
u_int32_t minor_version; |
||||
u_int32_t build_number; |
||||
u_int32_t platform_id; |
||||
MDRVA csd_version_rva; /* MDString further identifying the
|
||||
* host OS. |
||||
* Windows: name of the installed OS |
||||
* service pack. |
||||
* Mac OS X: the Apple OS build number |
||||
* (sw_vers -buildVersion). |
||||
* Linux: uname -srvmo */ |
||||
|
||||
u_int16_t suite_mask; /* Windows: VER_SUITE_* from WinNT.h */ |
||||
u_int16_t reserved2; |
||||
|
||||
MDCPUInformation cpu; |
||||
} MDRawSystemInfo; /* MINIDUMP_SYSTEM_INFO */ |
||||
|
||||
/* For (MDRawSystemInfo).processor_architecture: */ |
||||
typedef enum { |
||||
MD_CPU_ARCHITECTURE_X86 = 0, /* PROCESSOR_ARCHITECTURE_INTEL */ |
||||
MD_CPU_ARCHITECTURE_MIPS = 1, /* PROCESSOR_ARCHITECTURE_MIPS */ |
||||
MD_CPU_ARCHITECTURE_ALPHA = 2, /* PROCESSOR_ARCHITECTURE_ALPHA */ |
||||
MD_CPU_ARCHITECTURE_PPC = 3, /* PROCESSOR_ARCHITECTURE_PPC */ |
||||
MD_CPU_ARCHITECTURE_SHX = 4, /* PROCESSOR_ARCHITECTURE_SHX
|
||||
* (Super-H) */ |
||||
MD_CPU_ARCHITECTURE_ARM = 5, /* PROCESSOR_ARCHITECTURE_ARM */ |
||||
MD_CPU_ARCHITECTURE_IA64 = 6, /* PROCESSOR_ARCHITECTURE_IA64 */ |
||||
MD_CPU_ARCHITECTURE_ALPHA64 = 7, /* PROCESSOR_ARCHITECTURE_ALPHA64 */ |
||||
MD_CPU_ARCHITECTURE_MSIL = 8, /* PROCESSOR_ARCHITECTURE_MSIL
|
||||
* (Microsoft Intermediate Language) */ |
||||
MD_CPU_ARCHITECTURE_AMD64 = 9, /* PROCESSOR_ARCHITECTURE_AMD64 */ |
||||
MD_CPU_ARCHITECTURE_X86_WIN64 = 10, |
||||
/* PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 (WoW64) */ |
||||
MD_CPU_ARCHITECTURE_SPARC = 0x8001, /* Breakpad-defined value for SPARC */ |
||||
MD_CPU_ARCHITECTURE_UNKNOWN = 0xffff /* PROCESSOR_ARCHITECTURE_UNKNOWN */ |
||||
} MDCPUArchitecture; |
||||
|
||||
/* For (MDRawSystemInfo).platform_id: */ |
||||
typedef enum { |
||||
MD_OS_WIN32S = 0, /* VER_PLATFORM_WIN32s (Windows 3.1) */ |
||||
MD_OS_WIN32_WINDOWS = 1, /* VER_PLATFORM_WIN32_WINDOWS (Windows 95-98-Me) */ |
||||
MD_OS_WIN32_NT = 2, /* VER_PLATFORM_WIN32_NT (Windows NT, 2000+) */ |
||||
MD_OS_WIN32_CE = 3, /* VER_PLATFORM_WIN32_CE, VER_PLATFORM_WIN32_HH
|
||||
* (Windows CE, Windows Mobile, "Handheld") */ |
||||
|
||||
/* The following values are Breakpad-defined. */ |
||||
MD_OS_UNIX = 0x8000, /* Generic Unix-ish */ |
||||
MD_OS_MAC_OS_X = 0x8101, /* Mac OS X/Darwin */ |
||||
MD_OS_LINUX = 0x8201, /* Linux */ |
||||
MD_OS_SOLARIS = 0x8202 /* Solaris */ |
||||
} MDOSPlatform; |
||||
|
||||
|
||||
typedef struct { |
||||
u_int32_t size_of_info; /* Length of entire MDRawMiscInfo structure. */ |
||||
u_int32_t flags1; |
||||
|
||||
/* The next field is only valid if flags1 contains
|
||||
* MD_MISCINFO_FLAGS1_PROCESS_ID. */ |
||||
u_int32_t process_id; |
||||
|
||||
/* The next 3 fields are only valid if flags1 contains
|
||||
* MD_MISCINFO_FLAGS1_PROCESS_TIMES. */ |
||||
u_int32_t process_create_time; /* time_t process started */ |
||||
u_int32_t process_user_time; /* seconds of user CPU time */ |
||||
u_int32_t process_kernel_time; /* seconds of kernel CPU time */ |
||||
|
||||
/* The following fields are not present in MINIDUMP_MISC_INFO but are
|
||||
* in MINIDUMP_MISC_INFO_2. When this struct is populated, these values |
||||
* may not be set. Use flags1 or sizeOfInfo to determine whether these |
||||
* values are present. These are only valid when flags1 contains |
||||
* MD_MISCINFO_FLAGS1_PROCESSOR_POWER_INFO. */ |
||||
u_int32_t processor_max_mhz; |
||||
u_int32_t processor_current_mhz; |
||||
u_int32_t processor_mhz_limit; |
||||
u_int32_t processor_max_idle_state; |
||||
u_int32_t processor_current_idle_state; |
||||
} MDRawMiscInfo; /* MINIDUMP_MISC_INFO, MINIDUMP_MISC_INFO2 */ |
||||
|
||||
#define MD_MISCINFO_SIZE 24 |
||||
#define MD_MISCINFO2_SIZE 44 |
||||
|
||||
/* For (MDRawMiscInfo).flags1. These values indicate which fields in the
|
||||
* MDRawMiscInfoStructure are valid. */ |
||||
typedef enum { |
||||
MD_MISCINFO_FLAGS1_PROCESS_ID = 0x00000001, |
||||
/* MINIDUMP_MISC1_PROCESS_ID */ |
||||
MD_MISCINFO_FLAGS1_PROCESS_TIMES = 0x00000002, |
||||
/* MINIDUMP_MISC1_PROCESS_TIMES */ |
||||
MD_MISCINFO_FLAGS1_PROCESSOR_POWER_INFO = 0x00000004 |
||||
/* MINIDUMP_MISC1_PROCESSOR_POWER_INFO */ |
||||
} MDMiscInfoFlags1; |
||||
|
||||
|
||||
/*
|
||||
* Breakpad extension types |
||||
*/ |
||||
|
||||
|
||||
typedef struct { |
||||
/* validity is a bitmask with values from MDBreakpadInfoValidity, indicating
|
||||
* which of the other fields in the structure are valid. */ |
||||
u_int32_t validity; |
||||
|
||||
/* Thread ID of the handler thread. dump_thread_id should correspond to
|
||||
* the thread_id of an MDRawThread in the minidump's MDRawThreadList if |
||||
* a dedicated thread in that list was used to produce the minidump. If |
||||
* the MDRawThreadList does not contain a dedicated thread used to produce |
||||
* the minidump, this field should be set to 0 and the validity field |
||||
* must not contain MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID. */ |
||||
u_int32_t dump_thread_id; |
||||
|
||||
/* Thread ID of the thread that requested the minidump be produced. As
|
||||
* with dump_thread_id, requesting_thread_id should correspond to the |
||||
* thread_id of an MDRawThread in the minidump's MDRawThreadList. For |
||||
* minidumps produced as a result of an exception, requesting_thread_id |
||||
* will be the same as the MDRawExceptionStream's thread_id field. For |
||||
* minidumps produced "manually" at the program's request, |
||||
* requesting_thread_id will indicate which thread caused the dump to be |
||||
* written. If the minidump was produced at the request of something |
||||
* other than a thread in the MDRawThreadList, this field should be set |
||||
* to 0 and the validity field must not contain |
||||
* MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID. */ |
||||
u_int32_t requesting_thread_id; |
||||
} MDRawBreakpadInfo; |
||||
|
||||
/* For (MDRawBreakpadInfo).validity: */ |
||||
typedef enum { |
||||
/* When set, the dump_thread_id field is valid. */ |
||||
MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID = 1 << 0, |
||||
|
||||
/* When set, the requesting_thread_id field is valid. */ |
||||
MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID = 1 << 1 |
||||
} MDBreakpadInfoValidity; |
||||
|
||||
typedef struct { |
||||
/* expression, function, and file are 0-terminated UTF-16 strings. They
|
||||
* may be truncated if necessary, but should always be 0-terminated when |
||||
* written to a file. |
||||
* Fixed-length strings are used because MiniDumpWriteDump doesn't offer |
||||
* a way for user streams to point to arbitrary RVAs for strings. */ |
||||
u_int16_t expression[128]; /* Assertion that failed... */ |
||||
u_int16_t function[128]; /* ...within this function... */ |
||||
u_int16_t file[128]; /* ...in this file... */ |
||||
u_int32_t line; /* ...at this line. */ |
||||
u_int32_t type; |
||||
} MDRawAssertionInfo; |
||||
|
||||
/* For (MDRawAssertionInfo).type: */ |
||||
typedef enum { |
||||
MD_ASSERTION_INFO_TYPE_UNKNOWN = 0, |
||||
|
||||
/* Used for assertions that would be raised by the MSVC CRT but are
|
||||
* directed to an invalid parameter handler instead. */ |
||||
MD_ASSERTION_INFO_TYPE_INVALID_PARAMETER, |
||||
|
||||
/* Used for assertions that would be raised by the MSVC CRT but are
|
||||
* directed to a pure virtual call handler instead. */ |
||||
MD_ASSERTION_INFO_TYPE_PURE_VIRTUAL_CALL |
||||
} MDAssertionInfoData; |
||||
|
||||
#if defined(_MSC_VER) |
||||
#pragma warning(pop) |
||||
#endif /* _MSC_VER */ |
||||
|
||||
|
||||
#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_FORMAT_H__ */ |
@ -0,0 +1,107 @@ |
||||
// Copyright (c) 2007, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
|
||||
|
||||
// minidump_size.h: Provides a C++ template for programmatic access to
|
||||
// the sizes of various types defined in minidump_format.h.
|
||||
//
|
||||
// Author: Mark Mentovai
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_SIZE_H__ |
||||
#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_SIZE_H__ |
||||
|
||||
#include <sys/types.h> |
||||
|
||||
#include "google_breakpad/common/minidump_format.h" |
||||
|
||||
namespace google_breakpad { |
||||
|
||||
template<typename T> |
||||
class minidump_size { |
||||
public: |
||||
static size_t size() { return sizeof(T); } |
||||
}; |
||||
|
||||
// Explicit specializations for variable-length types. The size returned
|
||||
// for these should be the size for an object without its variable-length
|
||||
// section.
|
||||
|
||||
template<> |
||||
class minidump_size<MDString> { |
||||
public: |
||||
static size_t size() { return MDString_minsize; } |
||||
}; |
||||
|
||||
template<> |
||||
class minidump_size<MDRawThreadList> { |
||||
public: |
||||
static size_t size() { return MDRawThreadList_minsize; } |
||||
}; |
||||
|
||||
template<> |
||||
class minidump_size<MDCVInfoPDB20> { |
||||
public: |
||||
static size_t size() { return MDCVInfoPDB20_minsize; } |
||||
}; |
||||
|
||||
template<> |
||||
class minidump_size<MDCVInfoPDB70> { |
||||
public: |
||||
static size_t size() { return MDCVInfoPDB70_minsize; } |
||||
}; |
||||
|
||||
template<> |
||||
class minidump_size<MDImageDebugMisc> { |
||||
public: |
||||
static size_t size() { return MDImageDebugMisc_minsize; } |
||||
}; |
||||
|
||||
template<> |
||||
class minidump_size<MDRawModuleList> { |
||||
public: |
||||
static size_t size() { return MDRawModuleList_minsize; } |
||||
}; |
||||
|
||||
template<> |
||||
class minidump_size<MDRawMemoryList> { |
||||
public: |
||||
static size_t size() { return MDRawMemoryList_minsize; } |
||||
}; |
||||
|
||||
// Explicit specialization for MDRawModule, for which sizeof may include
|
||||
// tail-padding on some architectures but not others.
|
||||
|
||||
template<> |
||||
class minidump_size<MDRawModule> { |
||||
public: |
||||
static size_t size() { return MD_MODULE_SIZE; } |
||||
}; |
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // GOOGLE_BREAKPAD_COMMON_MINIDUMP_SIZE_H__
|
@ -0,0 +1,114 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// BasicSourceLineResolver implements SourceLineResolverInterface, using
|
||||
// address map files produced by a compatible writer, e.g. PDBSourceLineWriter.
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_PROCESSOR_BASIC_SOURCE_LINE_RESOLVER_H__ |
||||
#define GOOGLE_BREAKPAD_PROCESSOR_BASIC_SOURCE_LINE_RESOLVER_H__ |
||||
|
||||
// TODO: Platforms that have no hash_map can use map, at the likely cost of
|
||||
// performance.
|
||||
#ifdef __SUNPRO_CC |
||||
#define BSLR_NO_HASH_MAP |
||||
#endif // __SUNPRO_CC
|
||||
|
||||
#ifdef BSLR_NO_HASH_MAP |
||||
#include <map> |
||||
#else // BSLR_NO_HASH_MAP
|
||||
#include <ext/hash_map> |
||||
#endif // BSLR_NO_HASH_MAP
|
||||
|
||||
#include "google_breakpad/processor/source_line_resolver_interface.h" |
||||
|
||||
namespace google_breakpad { |
||||
|
||||
using std::string; |
||||
#ifdef BSLR_NO_HASH_MAP |
||||
using std::map; |
||||
#else // BSLR_NO_HASH_MAP
|
||||
using __gnu_cxx::hash_map; |
||||
#endif // BSLR_NO_HASH_MAP
|
||||
|
||||
class BasicSourceLineResolver : public SourceLineResolverInterface { |
||||
public: |
||||
BasicSourceLineResolver(); |
||||
virtual ~BasicSourceLineResolver(); |
||||
|
||||
// SourceLineResolverInterface methods, see source_line_resolver_interface.h
|
||||
// for more details.
|
||||
|
||||
// Adds a module to this resolver, returning true on success.
|
||||
// The given map_file is read into memory, and its symbols will be
|
||||
// retained until the BasicSourceLineResolver is destroyed.
|
||||
virtual bool LoadModule(const string &module_name, const string &map_file); |
||||
|
||||
// Exactly the same as above, except the given map_buffer is used
|
||||
// for symbols.
|
||||
virtual bool LoadModuleUsingMapBuffer(const string &module_name, |
||||
const string &map_buffer); |
||||
|
||||
|
||||
virtual bool HasModule(const string &module_name) const; |
||||
|
||||
virtual StackFrameInfo* FillSourceLineInfo(StackFrame *frame) const; |
||||
|
||||
private: |
||||
template<class T> class MemAddrMap; |
||||
struct Line; |
||||
struct Function; |
||||
struct PublicSymbol; |
||||
struct File; |
||||
#ifdef BSLR_NO_HASH_MAP |
||||
struct CompareString { |
||||
bool operator()(const string &s1, const string &s2) const; |
||||
}; |
||||
#else // BSLR_NO_HASH_MAP
|
||||
struct HashString { |
||||
size_t operator()(const string &s) const; |
||||
}; |
||||
#endif // BSLR_NO_HASH_MAP
|
||||
class Module; |
||||
|
||||
// All of the modules we've loaded
|
||||
#ifdef BSLR_NO_HASH_MAP |
||||
typedef map<string, Module*, CompareString> ModuleMap; |
||||
#else // BSLR_NO_HASH_MAP
|
||||
typedef hash_map<string, Module*, HashString> ModuleMap; |
||||
#endif // BSLR_NO_HASH_MAP
|
||||
ModuleMap *modules_; |
||||
|
||||
// Disallow unwanted copy ctor and assignment operator
|
||||
BasicSourceLineResolver(const BasicSourceLineResolver&); |
||||
void operator=(const BasicSourceLineResolver&); |
||||
}; |
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // GOOGLE_BREAKPAD_PROCESSOR_BASIC_SOURCE_LINE_RESOLVER_H__
|
@ -0,0 +1,77 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// call_stack.h: A call stack comprised of stack frames.
|
||||
//
|
||||
// This class manages a vector of stack frames. It is used instead of
|
||||
// exposing the vector directly to allow the CallStack to own StackFrame
|
||||
// pointers without having to publicly export the linked_ptr class. A
|
||||
// CallStack must be composed of pointers instead of objects to allow for
|
||||
// CPU-specific StackFrame subclasses.
|
||||
//
|
||||
// By convention, the stack frame at index 0 is the innermost callee frame,
|
||||
// and the frame at the highest index in a call stack is the outermost
|
||||
// caller. CallStack only allows stacks to be built by pushing frames,
|
||||
// beginning with the innermost callee frame.
|
||||
//
|
||||
// Author: Mark Mentovai
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_PROCESSOR_CALL_STACK_H__ |
||||
#define GOOGLE_BREAKPAD_PROCESSOR_CALL_STACK_H__ |
||||
|
||||
#include <vector> |
||||
|
||||
namespace google_breakpad { |
||||
|
||||
using std::vector; |
||||
|
||||
struct StackFrame; |
||||
template<typename T> class linked_ptr; |
||||
|
||||
class CallStack { |
||||
public: |
||||
CallStack() { Clear(); } |
||||
~CallStack(); |
||||
|
||||
// Resets the CallStack to its initial empty state
|
||||
void Clear(); |
||||
|
||||
const vector<StackFrame*>* frames() const { return &frames_; } |
||||
|
||||
private: |
||||
// Stackwalker is responsible for building the frames_ vector.
|
||||
friend class Stackwalker; |
||||
|
||||
// Storage for pushed frames.
|
||||
vector<StackFrame*> frames_; |
||||
}; |
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // GOOGLE_BREAKPAD_PROCSSOR_CALL_STACK_H__
|
@ -0,0 +1,94 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// code_module.h: Carries information about code modules that are loaded
|
||||
// into a process.
|
||||
//
|
||||
// Author: Mark Mentovai
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_PROCESSOR_CODE_MODULE_H__ |
||||
#define GOOGLE_BREAKPAD_PROCESSOR_CODE_MODULE_H__ |
||||
|
||||
#include <string> |
||||
#include "google_breakpad/common/breakpad_types.h" |
||||
|
||||
namespace google_breakpad { |
||||
|
||||
using std::string; |
||||
|
||||
class CodeModule { |
||||
public: |
||||
virtual ~CodeModule() {} |
||||
|
||||
// The base address of this code module as it was loaded by the process.
|
||||
// (u_int64_t)-1 on error.
|
||||
virtual u_int64_t base_address() const = 0; |
||||
|
||||
// The size of the code module. 0 on error.
|
||||
virtual u_int64_t size() const = 0; |
||||
|
||||
// The path or file name that the code module was loaded from. Empty on
|
||||
// error.
|
||||
virtual string code_file() const = 0; |
||||
|
||||
// An identifying string used to discriminate between multiple versions and
|
||||
// builds of the same code module. This may contain a uuid, timestamp,
|
||||
// version number, or any combination of this or other information, in an
|
||||
// implementation-defined format. Empty on error.
|
||||
virtual string code_identifier() const = 0; |
||||
|
||||
// The filename containing debugging information associated with the code
|
||||
// module. If debugging information is stored in a file separate from the
|
||||
// code module itself (as is the case when .pdb or .dSYM files are used),
|
||||
// this will be different from code_file. If debugging information is
|
||||
// stored in the code module itself (possibly prior to stripping), this
|
||||
// will be the same as code_file. Empty on error.
|
||||
virtual string debug_file() const = 0; |
||||
|
||||
// An identifying string similar to code_identifier, but identifies a
|
||||
// specific version and build of the associated debug file. This may be
|
||||
// the same as code_identifier when the debug_file and code_file are
|
||||
// identical or when the same identifier is used to identify distinct
|
||||
// debug and code files.
|
||||
virtual string debug_identifier() const = 0; |
||||
|
||||
// A human-readable representation of the code module's version. Empty on
|
||||
// error.
|
||||
virtual string version() const = 0; |
||||
|
||||
// Creates a new copy of this CodeModule object, which the caller takes
|
||||
// ownership of. The new CodeModule may be of a different concrete class
|
||||
// than the CodeModule being copied, but will behave identically to the
|
||||
// copied CodeModule as far as the CodeModule interface is concerned.
|
||||
virtual const CodeModule* Copy() const = 0; |
||||
}; |
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // GOOGLE_BREAKPAD_PROCESSOR_CODE_MODULE_H__
|
@ -0,0 +1,98 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// code_modules.h: Contains all of the CodeModule objects that were loaded
|
||||
// into a single process.
|
||||
//
|
||||
// Author: Mark Mentovai
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_PROCESSOR_CODE_MODULES_H__ |
||||
#define GOOGLE_BREAKPAD_PROCESSOR_CODE_MODULES_H__ |
||||
|
||||
#include "google_breakpad/common/breakpad_types.h" |
||||
|
||||
namespace google_breakpad { |
||||
|
||||
class CodeModule; |
||||
|
||||
class CodeModules { |
||||
public: |
||||
virtual ~CodeModules() {} |
||||
|
||||
// The number of contained CodeModule objects.
|
||||
virtual unsigned int module_count() const = 0; |
||||
|
||||
// Random access to modules. Returns the module whose code is present
|
||||
// at the address indicated by |address|. If no module is present at this
|
||||
// address, returns NULL. Ownership of the returned CodeModule is retained
|
||||
// by the CodeModules object; pointers returned by this method are valid for
|
||||
// comparison with pointers returned by the other Get methods.
|
||||
virtual const CodeModule* GetModuleForAddress(u_int64_t address) const = 0; |
||||
|
||||
// Returns the module corresponding to the main executable. If there is
|
||||
// no main executable, returns NULL. Ownership of the returned CodeModule
|
||||
// is retained by the CodeModules object; pointers returned by this method
|
||||
// are valid for comparison with pointers returned by the other Get
|
||||
// methods.
|
||||
virtual const CodeModule* GetMainModule() const = 0; |
||||
|
||||
// Sequential access to modules. A sequence number of 0 corresponds to the
|
||||
// module residing lowest in memory. If the sequence number is out of
|
||||
// range, returns NULL. Ownership of the returned CodeModule is retained
|
||||
// by the CodeModules object; pointers returned by this method are valid for
|
||||
// comparison with pointers returned by the other Get methods.
|
||||
virtual const CodeModule* GetModuleAtSequence( |
||||
unsigned int sequence) const = 0; |
||||
|
||||
// Sequential access to modules. This is similar to GetModuleAtSequence,
|
||||
// except no ordering requirement is enforced. A CodeModules implementation
|
||||
// may return CodeModule objects from GetModuleAtIndex in any order it
|
||||
// wishes, provided that the order remain the same throughout the life of
|
||||
// the CodeModules object. Typically, GetModuleAtIndex would be used by
|
||||
// a caller to enumerate all CodeModule objects quickly when the enumeration
|
||||
// does not require any ordering. If the index argument is out of range,
|
||||
// returns NULL. Ownership of the returned CodeModule is retained by
|
||||
// the CodeModules object; pointers returned by this method are valid for
|
||||
// comparison with pointers returned by the other Get methods.
|
||||
virtual const CodeModule* GetModuleAtIndex(unsigned int index) const = 0; |
||||
|
||||
// Creates a new copy of this CodeModules object, which the caller takes
|
||||
// ownership of. The new object will also contain copies of the existing
|
||||
// object's child CodeModule objects. The new CodeModules object may be of
|
||||
// a different concrete class than the object being copied, but will behave
|
||||
// identically to the copied object as far as the CodeModules and CodeModule
|
||||
// interfaces are concerned, except that the order that GetModuleAtIndex
|
||||
// returns objects in may differ between a copy and the original CodeModules
|
||||
// object.
|
||||
virtual const CodeModules* Copy() const = 0; |
||||
}; |
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // GOOGLE_BREAKPAD_PROCESSOR_CODE_MODULES_H__
|
@ -0,0 +1,76 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// memory_region.h: Access to memory regions.
|
||||
//
|
||||
// A MemoryRegion provides virtual access to a range of memory. It is an
|
||||
// abstraction allowing the actual source of memory to be independent of
|
||||
// methods which need to access a virtual memory space.
|
||||
//
|
||||
// Author: Mark Mentovai
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_PROCESSOR_MEMORY_REGION_H__ |
||||
#define GOOGLE_BREAKPAD_PROCESSOR_MEMORY_REGION_H__ |
||||
|
||||
|
||||
#include "google_breakpad/common/breakpad_types.h" |
||||
|
||||
|
||||
namespace google_breakpad { |
||||
|
||||
|
||||
class MemoryRegion { |
||||
public: |
||||
virtual ~MemoryRegion() {} |
||||
|
||||
// The base address of this memory region.
|
||||
virtual u_int64_t GetBase() = 0; |
||||
|
||||
// The size of this memory region.
|
||||
virtual u_int32_t GetSize() = 0; |
||||
|
||||
// Access to data of various sizes within the memory region. address
|
||||
// is a pointer to read, and it must lie within the memory region as
|
||||
// defined by its base address and size. The location pointed to by
|
||||
// value is set to the value at address. Byte-swapping is performed
|
||||
// if necessary so that the value is appropriate for the running
|
||||
// program. Returns true on success. Fails and returns false if address
|
||||
// is out of the region's bounds (after considering the width of value),
|
||||
// or for other types of errors.
|
||||
virtual bool GetMemoryAtAddress(u_int64_t address, u_int8_t* value) = 0; |
||||
virtual bool GetMemoryAtAddress(u_int64_t address, u_int16_t* value) = 0; |
||||
virtual bool GetMemoryAtAddress(u_int64_t address, u_int32_t* value) = 0; |
||||
virtual bool GetMemoryAtAddress(u_int64_t address, u_int64_t* value) = 0; |
||||
}; |
||||
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
|
||||
#endif // GOOGLE_BREAKPAD_PROCESSOR_MEMORY_REGION_H__
|
@ -0,0 +1,904 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// minidump.h: A minidump reader.
|
||||
//
|
||||
// The basic structure of this module tracks the structure of the minidump
|
||||
// file itself. At the top level, a minidump file is represented by a
|
||||
// Minidump object. Like most other classes in this module, Minidump
|
||||
// provides a Read method that initializes the object with information from
|
||||
// the file. Most of the classes in this file are wrappers around the
|
||||
// "raw" structures found in the minidump file itself, and defined in
|
||||
// minidump_format.h. For example, each thread is represented by a
|
||||
// MinidumpThread object, whose parameters are specified in an MDRawThread
|
||||
// structure. A properly byte-swapped MDRawThread can be obtained from a
|
||||
// MinidumpThread easily by calling its thread() method.
|
||||
//
|
||||
// Most of the module lazily reads only the portion of the minidump file
|
||||
// necessary to fulfill the user's request. Calling Minidump::Read
|
||||
// only reads the minidump's directory. The thread list is not read until
|
||||
// it is needed, and even once it's read, the memory regions for each
|
||||
// thread's stack aren't read until they're needed. This strategy avoids
|
||||
// unnecessary file input, and allocating memory for data in which the user
|
||||
// has no interest. Note that although memory allocations for a typical
|
||||
// minidump file are not particularly large, it is possible for legitimate
|
||||
// minidumps to be sizable. A full-memory minidump, for example, contains
|
||||
// a snapshot of the entire mapped memory space. Even a normal minidump,
|
||||
// with stack memory only, can be large if, for example, the dump was
|
||||
// generated in response to a crash that occurred due to an infinite-
|
||||
// recursion bug that caused the stack's limits to be exceeded. Finally,
|
||||
// some users of this library will unfortunately find themselves in the
|
||||
// position of having to process potentially-hostile minidumps that might
|
||||
// attempt to cause problems by forcing the minidump processor to over-
|
||||
// allocate memory.
|
||||
//
|
||||
// Memory management in this module is based on a strict
|
||||
// you-don't-own-anything policy. The only object owned by the user is
|
||||
// the top-level Minidump object, the creation and destruction of which
|
||||
// must be the user's own responsibility. All other objects obtained
|
||||
// through interaction with this module are ultimately owned by the
|
||||
// Minidump object, and will be freed upon the Minidump object's destruction.
|
||||
// Because memory regions can potentially involve large allocations, a
|
||||
// FreeMemory method is provided by MinidumpMemoryRegion, allowing the user
|
||||
// to release data when it is no longer needed. Use of this method is
|
||||
// optional but recommended. If freed data is later required, it will
|
||||
// be read back in from the minidump file again.
|
||||
//
|
||||
// There is one exception to this memory management policy:
|
||||
// Minidump::ReadString will return a string object to the user, and the user
|
||||
// is responsible for its deletion.
|
||||
//
|
||||
// Author: Mark Mentovai
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_PROCESSOR_MINIDUMP_H__ |
||||
#define GOOGLE_BREAKPAD_PROCESSOR_MINIDUMP_H__ |
||||
|
||||
#include <unistd.h> |
||||
|
||||
#include <map> |
||||
#include <string> |
||||
#include <vector> |
||||
|
||||
#include "google_breakpad/common/minidump_format.h" |
||||
#include "google_breakpad/processor/code_module.h" |
||||
#include "google_breakpad/processor/code_modules.h" |
||||
#include "google_breakpad/processor/memory_region.h" |
||||
|
||||
|
||||
namespace google_breakpad { |
||||
|
||||
|
||||
using std::map; |
||||
using std::string; |
||||
using std::vector; |
||||
|
||||
|
||||
class Minidump; |
||||
template<typename AddressType, typename EntryType> class RangeMap; |
||||
|
||||
|
||||
// MinidumpObject is the base of all Minidump* objects except for Minidump
|
||||
// itself.
|
||||
class MinidumpObject { |
||||
public: |
||||
virtual ~MinidumpObject() {} |
||||
|
||||
bool valid() const { return valid_; } |
||||
|
||||
protected: |
||||
explicit MinidumpObject(Minidump* minidump); |
||||
|
||||
// Refers to the Minidump object that is the ultimate parent of this
|
||||
// Some MinidumpObjects are owned by other MinidumpObjects, but at the
|
||||
// root of the ownership tree is always a Minidump. The Minidump object
|
||||
// is kept here for access to its seeking and reading facilities, and
|
||||
// for access to data about the minidump file itself, such as whether
|
||||
// it should be byte-swapped.
|
||||
Minidump* minidump_; |
||||
|
||||
// MinidumpObjects are not valid when created. When a subclass populates
|
||||
// its own fields, it can set valid_ to true. Accessors and mutators may
|
||||
// wish to consider or alter the valid_ state as they interact with
|
||||
// objects.
|
||||
bool valid_; |
||||
}; |
||||
|
||||
|
||||
// This class exists primarily to provide a virtual destructor in a base
|
||||
// class common to all objects that might be stored in
|
||||
// Minidump::mStreamObjects. Some object types (MinidumpContext) will
|
||||
// never be stored in Minidump::mStreamObjects, but are represented as
|
||||
// streams and adhere to the same interface, and may be derived from
|
||||
// this class.
|
||||
class MinidumpStream : public MinidumpObject { |
||||
public: |
||||
virtual ~MinidumpStream() {} |
||||
|
||||
protected: |
||||
explicit MinidumpStream(Minidump* minidump); |
||||
|
||||
private: |
||||
// Populate (and validate) the MinidumpStream. minidump_ is expected
|
||||
// to be positioned at the beginning of the stream, so that the next
|
||||
// read from the minidump will be at the beginning of the stream.
|
||||
// expected_size should be set to the stream's length as contained in
|
||||
// the MDRawDirectory record or other identifying record. A class
|
||||
// that implements MinidumpStream can compare expected_size to a
|
||||
// known size as an integrity check.
|
||||
virtual bool Read(u_int32_t expected_size) = 0; |
||||
}; |
||||
|
||||
|
||||
// MinidumpContext carries a CPU-specific MDRawContext structure, which
|
||||
// contains CPU context such as register states. Each thread has its
|
||||
// own context, and the exception record, if present, also has its own
|
||||
// context. Note that if the exception record is present, the context it
|
||||
// refers to is probably what the user wants to use for the exception
|
||||
// thread, instead of that thread's own context. The exception thread's
|
||||
// context (as opposed to the exception record's context) will contain
|
||||
// context for the exception handler (which performs minidump generation),
|
||||
// and not the context that caused the exception (which is probably what the
|
||||
// user wants).
|
||||
class MinidumpContext : public MinidumpStream { |
||||
public: |
||||
virtual ~MinidumpContext(); |
||||
|
||||
// Returns an MD_CONTEXT_* value such as MD_CONTEXT_X86 or MD_CONTEXT_PPC
|
||||
// identifying the CPU type that the context was collected from. The
|
||||
// returned value will identify the CPU only, and will have any other
|
||||
// MD_CONTEXT_* bits masked out. Returns 0 on failure.
|
||||
u_int32_t GetContextCPU() const; |
||||
|
||||
// Returns raw CPU-specific context data for the named CPU type. If the
|
||||
// context data does not match the CPU type or does not exist, returns
|
||||
// NULL.
|
||||
const MDRawContextX86* GetContextX86() const; |
||||
const MDRawContextPPC* GetContextPPC() const; |
||||
const MDRawContextAMD64* GetContextAMD64() const; |
||||
const MDRawContextSPARC* GetContextSPARC() const; |
||||
|
||||
// Print a human-readable representation of the object to stdout.
|
||||
void Print(); |
||||
|
||||
private: |
||||
friend class MinidumpThread; |
||||
friend class MinidumpException; |
||||
|
||||
explicit MinidumpContext(Minidump* minidump); |
||||
|
||||
bool Read(u_int32_t expected_size); |
||||
|
||||
// Free the CPU-specific context structure.
|
||||
void FreeContext(); |
||||
|
||||
// If the minidump contains a SYSTEM_INFO_STREAM, makes sure that the
|
||||
// system info stream gives an appropriate CPU type matching the context
|
||||
// CPU type in context_cpu_type. Returns false if the CPU type does not
|
||||
// match. Returns true if the CPU type matches or if the minidump does
|
||||
// not contain a system info stream.
|
||||
bool CheckAgainstSystemInfo(u_int32_t context_cpu_type); |
||||
|
||||
// Store this separately because of the weirdo AMD64 context
|
||||
u_int32_t context_flags_; |
||||
|
||||
// The CPU-specific context structure.
|
||||
union { |
||||
MDRawContextBase* base; |
||||
MDRawContextX86* x86; |
||||
MDRawContextPPC* ppc; |
||||
MDRawContextAMD64* amd64; |
||||
// on Solaris SPARC, sparc is defined as a numeric constant,
|
||||
// so variables can NOT be named as sparc
|
||||
MDRawContextSPARC* ctx_sparc; |
||||
} context_; |
||||
}; |
||||
|
||||
|
||||
// MinidumpMemoryRegion does not wrap any MDRaw structure, and only contains
|
||||
// a reference to an MDMemoryDescriptor. This object is intended to wrap
|
||||
// portions of a minidump file that contain memory dumps. In normal
|
||||
// minidumps, each MinidumpThread owns a MinidumpMemoryRegion corresponding
|
||||
// to the thread's stack memory. MinidumpMemoryList also gives access to
|
||||
// memory regions in its list as MinidumpMemoryRegions. This class
|
||||
// adheres to MemoryRegion so that it may be used as a data provider to
|
||||
// the Stackwalker family of classes.
|
||||
class MinidumpMemoryRegion : public MinidumpObject, |
||||
public MemoryRegion { |
||||
public: |
||||
virtual ~MinidumpMemoryRegion(); |
||||
|
||||
static void set_max_bytes(u_int32_t max_bytes) { max_bytes_ = max_bytes; } |
||||
static u_int32_t max_bytes() { return max_bytes_; } |
||||
|
||||
// Returns a pointer to the base of the memory region. Returns the
|
||||
// cached value if available, otherwise, reads the minidump file and
|
||||
// caches the memory region.
|
||||
const u_int8_t* GetMemory(); |
||||
|
||||
// The address of the base of the memory region.
|
||||
u_int64_t GetBase(); |
||||
|
||||
// The size, in bytes, of the memory region.
|
||||
u_int32_t GetSize(); |
||||
|
||||
// Frees the cached memory region, if cached.
|
||||
void FreeMemory(); |
||||
|
||||
// Obtains the value of memory at the pointer specified by address.
|
||||
bool GetMemoryAtAddress(u_int64_t address, u_int8_t* value); |
||||
bool GetMemoryAtAddress(u_int64_t address, u_int16_t* value); |
||||
bool GetMemoryAtAddress(u_int64_t address, u_int32_t* value); |
||||
bool GetMemoryAtAddress(u_int64_t address, u_int64_t* value); |
||||
|
||||
// Print a human-readable representation of the object to stdout.
|
||||
void Print(); |
||||
|
||||
private: |
||||
friend class MinidumpThread; |
||||
friend class MinidumpMemoryList; |
||||
|
||||
explicit MinidumpMemoryRegion(Minidump* minidump); |
||||
|
||||
// Identify the base address and size of the memory region, and the
|
||||
// location it may be found in the minidump file.
|
||||
void SetDescriptor(MDMemoryDescriptor* descriptor); |
||||
|
||||
// Implementation for GetMemoryAtAddress
|
||||
template<typename T> bool GetMemoryAtAddressInternal(u_int64_t address, |
||||
T* value); |
||||
|
||||
// The largest memory region that will be read from a minidump. The
|
||||
// default is 1MB.
|
||||
static u_int32_t max_bytes_; |
||||
|
||||
// Base address and size of the memory region, and its position in the
|
||||
// minidump file.
|
||||
MDMemoryDescriptor* descriptor_; |
||||
|
||||
// Cached memory.
|
||||
vector<u_int8_t>* memory_; |
||||
}; |
||||
|
||||
|
||||
// MinidumpThread contains information about a thread of execution,
|
||||
// including a snapshot of the thread's stack and CPU context. For
|
||||
// the thread that caused an exception, the context carried by
|
||||
// MinidumpException is probably desired instead of the CPU context
|
||||
// provided here.
|
||||
class MinidumpThread : public MinidumpObject { |
||||
public: |
||||
virtual ~MinidumpThread(); |
||||
|
||||
const MDRawThread* thread() const { return valid_ ? &thread_ : NULL; } |
||||
MinidumpMemoryRegion* GetMemory(); |
||||
MinidumpContext* GetContext(); |
||||
|
||||
// The thread ID is used to determine if a thread is the exception thread,
|
||||
// so a special getter is provided to retrieve this data from the
|
||||
// MDRawThread structure. Returns false if the thread ID cannot be
|
||||
// determined.
|
||||
bool GetThreadID(u_int32_t *thread_id) const; |
||||
|
||||
// Print a human-readable representation of the object to stdout.
|
||||
void Print(); |
||||
|
||||
private: |
||||
// These objects are managed by MinidumpThreadList.
|
||||
friend class MinidumpThreadList; |
||||
|
||||
explicit MinidumpThread(Minidump* minidump); |
||||
|
||||
// This works like MinidumpStream::Read, but is driven by
|
||||
// MinidumpThreadList. No size checking is done, because
|
||||
// MinidumpThreadList handles that directly.
|
||||
bool Read(); |
||||
|
||||
MDRawThread thread_; |
||||
MinidumpMemoryRegion* memory_; |
||||
MinidumpContext* context_; |
||||
}; |
||||
|
||||
|
||||
// MinidumpThreadList contains all of the threads (as MinidumpThreads) in
|
||||
// a process.
|
||||
class MinidumpThreadList : public MinidumpStream { |
||||
public: |
||||
virtual ~MinidumpThreadList(); |
||||
|
||||
static void set_max_threads(u_int32_t max_threads) { |
||||
max_threads_ = max_threads; |
||||
} |
||||
static u_int32_t max_threads() { return max_threads_; } |
||||
|
||||
unsigned int thread_count() const { return valid_ ? thread_count_ : 0; } |
||||
|
||||
// Sequential access to threads.
|
||||
MinidumpThread* GetThreadAtIndex(unsigned int index) const; |
||||
|
||||
// Random access to threads.
|
||||
MinidumpThread* GetThreadByID(u_int32_t thread_id); |
||||
|
||||
// Print a human-readable representation of the object to stdout.
|
||||
void Print(); |
||||
|
||||
private: |
||||
friend class Minidump; |
||||
|
||||
typedef map<u_int32_t, MinidumpThread*> IDToThreadMap; |
||||
typedef vector<MinidumpThread> MinidumpThreads; |
||||
|
||||
static const u_int32_t kStreamType = MD_THREAD_LIST_STREAM; |
||||
|
||||
explicit MinidumpThreadList(Minidump* aMinidump); |
||||
|
||||
bool Read(u_int32_t aExpectedSize); |
||||
|
||||
// The largest number of threads that will be read from a minidump. The
|
||||
// default is 256.
|
||||
static u_int32_t max_threads_; |
||||
|
||||
// Access to threads using the thread ID as the key.
|
||||
IDToThreadMap id_to_thread_map_; |
||||
|
||||
// The list of threads.
|
||||
MinidumpThreads* threads_; |
||||
u_int32_t thread_count_; |
||||
}; |
||||
|
||||
|
||||
// MinidumpModule wraps MDRawModule, which contains information about loaded
|
||||
// code modules. Access is provided to various data referenced indirectly
|
||||
// by MDRawModule, such as the module's name and a specification for where
|
||||
// to locate debugging information for the module.
|
||||
class MinidumpModule : public MinidumpObject, |
||||
public CodeModule { |
||||
public: |
||||
virtual ~MinidumpModule(); |
||||
|
||||
static void set_max_cv_bytes(u_int32_t max_cv_bytes) { |
||||
max_cv_bytes_ = max_cv_bytes; |
||||
} |
||||
static u_int32_t max_cv_bytes() { return max_cv_bytes_; } |
||||
|
||||
static void set_max_misc_bytes(u_int32_t max_misc_bytes) { |
||||
max_misc_bytes_ = max_misc_bytes; |
||||
} |
||||
static u_int32_t max_misc_bytes() { return max_misc_bytes_; } |
||||
|
||||
const MDRawModule* module() const { return valid_ ? &module_ : NULL; } |
||||
|
||||
// CodeModule implementation
|
||||
virtual u_int64_t base_address() const { |
||||
return valid_ ? module_.base_of_image : static_cast<u_int64_t>(-1); |
||||
} |
||||
virtual u_int64_t size() const { return valid_ ? module_.size_of_image : 0; } |
||||
virtual string code_file() const; |
||||
virtual string code_identifier() const; |
||||
virtual string debug_file() const; |
||||
virtual string debug_identifier() const; |
||||
virtual string version() const; |
||||
virtual const CodeModule* Copy() const; |
||||
|
||||
// The CodeView record, which contains information to locate the module's
|
||||
// debugging information (pdb). This is returned as u_int8_t* because
|
||||
// the data can be of types MDCVInfoPDB20* or MDCVInfoPDB70*, or it may be
|
||||
// of a type unknown to Breakpad, in which case the raw data will still be
|
||||
// returned but no byte-swapping will have been performed. Check the
|
||||
// record's signature in the first four bytes to differentiate between
|
||||
// the various types. Current toolchains generate modules which carry
|
||||
// MDCVInfoPDB70 by default. Returns a pointer to the CodeView record on
|
||||
// success, and NULL on failure. On success, the optional |size| argument
|
||||
// is set to the size of the CodeView record.
|
||||
const u_int8_t* GetCVRecord(u_int32_t* size); |
||||
|
||||
// The miscellaneous debug record, which is obsolete. Current toolchains
|
||||
// do not generate this type of debugging information (dbg), and this
|
||||
// field is not expected to be present. Returns a pointer to the debugging
|
||||
// record on success, and NULL on failure. On success, the optional |size|
|
||||
// argument is set to the size of the debugging record.
|
||||
const MDImageDebugMisc* GetMiscRecord(u_int32_t* size); |
||||
|
||||
// Print a human-readable representation of the object to stdout.
|
||||
void Print(); |
||||
|
||||
private: |
||||
// These objects are managed by MinidumpModuleList.
|
||||
friend class MinidumpModuleList; |
||||
|
||||
explicit MinidumpModule(Minidump* minidump); |
||||
|
||||
// This works like MinidumpStream::Read, but is driven by
|
||||
// MinidumpModuleList. No size checking is done, because
|
||||
// MinidumpModuleList handles that directly.
|
||||
bool Read(); |
||||
|
||||
// Reads indirectly-referenced data, including the module name, CodeView
|
||||
// record, and miscellaneous debugging record. This is necessary to allow
|
||||
// MinidumpModuleList to fully construct MinidumpModule objects without
|
||||
// requiring seeks to read a contiguous set of MinidumpModule objects.
|
||||
// All auxiliary data should be available when Read is called, in order to
|
||||
// allow the CodeModule getters to be const methods.
|
||||
bool ReadAuxiliaryData(); |
||||
|
||||
// The largest number of bytes that will be read from a minidump for a
|
||||
// CodeView record or miscellaneous debugging record, respectively. The
|
||||
// default for each is 1024.
|
||||
static u_int32_t max_cv_bytes_; |
||||
static u_int32_t max_misc_bytes_; |
||||
|
||||
// True after a successful Read. This is different from valid_, which is
|
||||
// not set true until ReadAuxiliaryData also completes successfully.
|
||||
// module_valid_ is only used by ReadAuxiliaryData and the functions it
|
||||
// calls to determine whether the object is ready for auxiliary data to
|
||||
// be read.
|
||||
bool module_valid_; |
||||
|
||||
// True if debug info was read from the module. Certain modules
|
||||
// may contain debug records in formats we don't support,
|
||||
// so we can just set this to false to ignore them.
|
||||
bool has_debug_info_; |
||||
|
||||
MDRawModule module_; |
||||
|
||||
// Cached module name.
|
||||
const string* name_; |
||||
|
||||
// Cached CodeView record - this is MDCVInfoPDB20 or (likely)
|
||||
// MDCVInfoPDB70, or possibly something else entirely. Stored as a u_int8_t
|
||||
// because the structure contains a variable-sized string and its exact
|
||||
// size cannot be known until it is processed.
|
||||
vector<u_int8_t>* cv_record_; |
||||
|
||||
// If cv_record_ is present, cv_record_signature_ contains a copy of the
|
||||
// CodeView record's first four bytes, for ease of determinining the
|
||||
// type of structure that cv_record_ contains.
|
||||
u_int32_t cv_record_signature_; |
||||
|
||||
// Cached MDImageDebugMisc (usually not present), stored as u_int8_t
|
||||
// because the structure contains a variable-sized string and its exact
|
||||
// size cannot be known until it is processed.
|
||||
vector<u_int8_t>* misc_record_; |
||||
}; |
||||
|
||||
|
||||
// MinidumpModuleList contains all of the loaded code modules for a process
|
||||
// in the form of MinidumpModules. It maintains a map of these modules
|
||||
// so that it may easily provide a code module corresponding to a specific
|
||||
// address.
|
||||
class MinidumpModuleList : public MinidumpStream, |
||||
public CodeModules { |
||||
public: |
||||
virtual ~MinidumpModuleList(); |
||||
|
||||
static void set_max_modules(u_int32_t max_modules) { |
||||
max_modules_ = max_modules; |
||||
} |
||||
static u_int32_t max_modules() { return max_modules_; } |
||||
|
||||
// CodeModules implementation.
|
||||
virtual unsigned int module_count() const { |
||||
return valid_ ? module_count_ : 0; |
||||
} |
||||
virtual const MinidumpModule* GetModuleForAddress(u_int64_t address) const; |
||||
virtual const MinidumpModule* GetMainModule() const; |
||||
virtual const MinidumpModule* GetModuleAtSequence( |
||||
unsigned int sequence) const; |
||||
virtual const MinidumpModule* GetModuleAtIndex(unsigned int index) const; |
||||
virtual const CodeModules* Copy() const; |
||||
|
||||
// Print a human-readable representation of the object to stdout.
|
||||
void Print(); |
||||
|
||||
private: |
||||
friend class Minidump; |
||||
|
||||
typedef vector<MinidumpModule> MinidumpModules; |
||||
|
||||
static const u_int32_t kStreamType = MD_MODULE_LIST_STREAM; |
||||
|
||||
explicit MinidumpModuleList(Minidump* minidump); |
||||
|
||||
bool Read(u_int32_t expected_size); |
||||
|
||||
// The largest number of modules that will be read from a minidump. The
|
||||
// default is 1024.
|
||||
static u_int32_t max_modules_; |
||||
|
||||
// Access to modules using addresses as the key.
|
||||
RangeMap<u_int64_t, unsigned int> *range_map_; |
||||
|
||||
MinidumpModules *modules_; |
||||
u_int32_t module_count_; |
||||
}; |
||||
|
||||
|
||||
// MinidumpMemoryList corresponds to a minidump's MEMORY_LIST_STREAM stream,
|
||||
// which references the snapshots of all of the memory regions contained
|
||||
// within the minidump. For a normal minidump, this includes stack memory
|
||||
// (also referenced by each MinidumpThread, in fact, the MDMemoryDescriptors
|
||||
// here and in MDRawThread both point to exactly the same data in a
|
||||
// minidump file, conserving space), as well as a 256-byte snapshot of memory
|
||||
// surrounding the instruction pointer in the case of an exception. Other
|
||||
// types of minidumps may contain significantly more memory regions. Full-
|
||||
// memory minidumps contain all of a process' mapped memory.
|
||||
class MinidumpMemoryList : public MinidumpStream { |
||||
public: |
||||
virtual ~MinidumpMemoryList(); |
||||
|
||||
static void set_max_regions(u_int32_t max_regions) { |
||||
max_regions_ = max_regions; |
||||
} |
||||
static u_int32_t max_regions() { return max_regions_; } |
||||
|
||||
unsigned int region_count() const { return valid_ ? region_count_ : 0; } |
||||
|
||||
// Sequential access to memory regions.
|
||||
MinidumpMemoryRegion* GetMemoryRegionAtIndex(unsigned int index); |
||||
|
||||
// Random access to memory regions. Returns the region encompassing
|
||||
// the address identified by address.
|
||||
MinidumpMemoryRegion* GetMemoryRegionForAddress(u_int64_t address); |
||||
|
||||
// Print a human-readable representation of the object to stdout.
|
||||
void Print(); |
||||
|
||||
private: |
||||
friend class Minidump; |
||||
|
||||
typedef vector<MDMemoryDescriptor> MemoryDescriptors; |
||||
typedef vector<MinidumpMemoryRegion> MemoryRegions; |
||||
|
||||
static const u_int32_t kStreamType = MD_MEMORY_LIST_STREAM; |
||||
|
||||
explicit MinidumpMemoryList(Minidump* minidump); |
||||
|
||||
bool Read(u_int32_t expected_size); |
||||
|
||||
// The largest number of memory regions that will be read from a minidump.
|
||||
// The default is 256.
|
||||
static u_int32_t max_regions_; |
||||
|
||||
// Access to memory regions using addresses as the key.
|
||||
RangeMap<u_int64_t, unsigned int> *range_map_; |
||||
|
||||
// The list of descriptors. This is maintained separately from the list
|
||||
// of regions, because MemoryRegion doesn't own its MemoryDescriptor, it
|
||||
// maintains a pointer to it. descriptors_ provides the storage for this
|
||||
// purpose.
|
||||
MemoryDescriptors *descriptors_; |
||||
|
||||
// The list of regions.
|
||||
MemoryRegions *regions_; |
||||
u_int32_t region_count_; |
||||
}; |
||||
|
||||
|
||||
// MinidumpException wraps MDRawExceptionStream, which contains information
|
||||
// about the exception that caused the minidump to be generated, if the
|
||||
// minidump was generated in an exception handler called as a result of
|
||||
// an exception. It also provides access to a MinidumpContext object,
|
||||
// which contains the CPU context for the exception thread at the time
|
||||
// the exception occurred.
|
||||
class MinidumpException : public MinidumpStream { |
||||
public: |
||||
virtual ~MinidumpException(); |
||||
|
||||
const MDRawExceptionStream* exception() const { |
||||
return valid_ ? &exception_ : NULL; |
||||
} |
||||
|
||||
// The thread ID is used to determine if a thread is the exception thread,
|
||||
// so a special getter is provided to retrieve this data from the
|
||||
// MDRawExceptionStream structure. Returns false if the thread ID cannot
|
||||
// be determined.
|
||||
bool GetThreadID(u_int32_t *thread_id) const; |
||||
|
||||
MinidumpContext* GetContext(); |
||||
|
||||
// Print a human-readable representation of the object to stdout.
|
||||
void Print(); |
||||
|
||||
private: |
||||
friend class Minidump; |
||||
|
||||
static const u_int32_t kStreamType = MD_EXCEPTION_STREAM; |
||||
|
||||
explicit MinidumpException(Minidump* minidump); |
||||
|
||||
bool Read(u_int32_t expected_size); |
||||
|
||||
MDRawExceptionStream exception_; |
||||
MinidumpContext* context_; |
||||
}; |
||||
|
||||
|
||||
// MinidumpSystemInfo wraps MDRawSystemInfo and provides information about
|
||||
// the system on which the minidump was generated. See also MinidumpMiscInfo.
|
||||
class MinidumpSystemInfo : public MinidumpStream { |
||||
public: |
||||
virtual ~MinidumpSystemInfo(); |
||||
|
||||
const MDRawSystemInfo* system_info() const { |
||||
return valid_ ? &system_info_ : NULL; |
||||
} |
||||
|
||||
// GetOS and GetCPU return textual representations of the operating system
|
||||
// and CPU that produced the minidump. Unlike most other Minidump* methods,
|
||||
// they return string objects, not weak pointers. Defined values for
|
||||
// GetOS() are "mac", "windows", and "linux". Defined values for GetCPU
|
||||
// are "x86" and "ppc". These methods return an empty string when their
|
||||
// values are unknown.
|
||||
string GetOS(); |
||||
string GetCPU(); |
||||
|
||||
// I don't know what CSD stands for, but this field is documented as
|
||||
// returning a textual representation of the OS service pack. On other
|
||||
// platforms, this provides additional information about an OS version
|
||||
// level beyond major.minor.micro. Returns NULL if unknown.
|
||||
const string* GetCSDVersion(); |
||||
|
||||
// If a CPU vendor string can be determined, returns a pointer to it,
|
||||
// otherwise, returns NULL. CPU vendor strings can be determined from
|
||||
// x86 CPUs with CPUID 0.
|
||||
const string* GetCPUVendor(); |
||||
|
||||
// Print a human-readable representation of the object to stdout.
|
||||
void Print(); |
||||
|
||||
private: |
||||
friend class Minidump; |
||||
|
||||
static const u_int32_t kStreamType = MD_SYSTEM_INFO_STREAM; |
||||
|
||||
explicit MinidumpSystemInfo(Minidump* minidump); |
||||
|
||||
bool Read(u_int32_t expected_size); |
||||
|
||||
MDRawSystemInfo system_info_; |
||||
|
||||
// Textual representation of the OS service pack, for minidumps produced
|
||||
// by MiniDumpWriteDump on Windows.
|
||||
const string* csd_version_; |
||||
|
||||
// A string identifying the CPU vendor, if known.
|
||||
const string* cpu_vendor_; |
||||
}; |
||||
|
||||
|
||||
// MinidumpMiscInfo wraps MDRawMiscInfo and provides information about
|
||||
// the process that generated the minidump, and optionally additional system
|
||||
// information. See also MinidumpSystemInfo.
|
||||
class MinidumpMiscInfo : public MinidumpStream { |
||||
public: |
||||
const MDRawMiscInfo* misc_info() const { |
||||
return valid_ ? &misc_info_ : NULL; |
||||
} |
||||
|
||||
// Print a human-readable representation of the object to stdout.
|
||||
void Print(); |
||||
|
||||
private: |
||||
friend class Minidump; |
||||
|
||||
static const u_int32_t kStreamType = MD_MISC_INFO_STREAM; |
||||
|
||||
explicit MinidumpMiscInfo(Minidump* minidump_); |
||||
|
||||
bool Read(u_int32_t expected_size_); |
||||
|
||||
MDRawMiscInfo misc_info_; |
||||
}; |
||||
|
||||
|
||||
// MinidumpBreakpadInfo wraps MDRawBreakpadInfo, which is an optional stream in
|
||||
// a minidump that provides additional information about the process state
|
||||
// at the time the minidump was generated.
|
||||
class MinidumpBreakpadInfo : public MinidumpStream { |
||||
public: |
||||
const MDRawBreakpadInfo* breakpad_info() const { |
||||
return valid_ ? &breakpad_info_ : NULL; |
||||
} |
||||
|
||||
// These thread IDs are used to determine if threads deserve special
|
||||
// treatment, so special getters are provided to retrieve this data from
|
||||
// the MDRawBreakpadInfo structure. The getters return false if the thread
|
||||
// IDs cannot be determined.
|
||||
bool GetDumpThreadID(u_int32_t *thread_id) const; |
||||
bool GetRequestingThreadID(u_int32_t *thread_id) const; |
||||
|
||||
// Print a human-readable representation of the object to stdout.
|
||||
void Print(); |
||||
|
||||
private: |
||||
friend class Minidump; |
||||
|
||||
static const u_int32_t kStreamType = MD_BREAKPAD_INFO_STREAM; |
||||
|
||||
explicit MinidumpBreakpadInfo(Minidump* minidump_); |
||||
|
||||
bool Read(u_int32_t expected_size_); |
||||
|
||||
MDRawBreakpadInfo breakpad_info_; |
||||
}; |
||||
|
||||
|
||||
// Minidump is the user's interface to a minidump file. It wraps MDRawHeader
|
||||
// and provides access to the minidump's top-level stream directory.
|
||||
class Minidump { |
||||
public: |
||||
// path is the pathname of a file containing the minidump.
|
||||
explicit Minidump(const string& path); |
||||
|
||||
~Minidump(); |
||||
|
||||
static void set_max_streams(u_int32_t max_streams) { |
||||
max_streams_ = max_streams; |
||||
} |
||||
static u_int32_t max_streams() { return max_streams_; } |
||||
|
||||
static void set_max_string_length(u_int32_t max_string_length) { |
||||
max_string_length_ = max_string_length; |
||||
} |
||||
static u_int32_t max_string_length() { return max_string_length_; } |
||||
|
||||
const MDRawHeader* header() const { return valid_ ? &header_ : NULL; } |
||||
|
||||
// Reads the minidump file's header and top-level stream directory.
|
||||
// The minidump is expected to be positioned at the beginning of the
|
||||
// header. Read() sets up the stream list and map, and validates the
|
||||
// Minidump object.
|
||||
bool Read(); |
||||
|
||||
// The next set of methods are stubs that call GetStream. They exist to
|
||||
// force code generation of the templatized API within the module, and
|
||||
// to avoid exposing an ugly API (GetStream needs to accept a garbage
|
||||
// parameter).
|
||||
MinidumpThreadList* GetThreadList(); |
||||
MinidumpModuleList* GetModuleList(); |
||||
MinidumpMemoryList* GetMemoryList(); |
||||
MinidumpException* GetException(); |
||||
MinidumpSystemInfo* GetSystemInfo(); |
||||
MinidumpMiscInfo* GetMiscInfo(); |
||||
MinidumpBreakpadInfo* GetBreakpadInfo(); |
||||
|
||||
// The next set of methods are provided for users who wish to access
|
||||
// data in minidump files directly, while leveraging the rest of
|
||||
// this class and related classes to handle the basic minidump
|
||||
// structure and known stream types.
|
||||
|
||||
unsigned int GetDirectoryEntryCount() const { |
||||
return valid_ ? header_.stream_count : 0; |
||||
} |
||||
const MDRawDirectory* GetDirectoryEntryAtIndex(unsigned int index) const; |
||||
|
||||
// The next 2 methods are lower-level I/O routines. They use fd_.
|
||||
|
||||
// Reads count bytes from the minidump at the current position into
|
||||
// the storage area pointed to by bytes. bytes must be of sufficient
|
||||
// size. After the read, the file position is advanced by count.
|
||||
bool ReadBytes(void* bytes, size_t count); |
||||
|
||||
// Sets the position of the minidump file to offset.
|
||||
bool SeekSet(off_t offset); |
||||
|
||||
// Returns the current position of the minidump file.
|
||||
off_t Tell() { return valid_ ? lseek(fd_, 0, SEEK_CUR) : (off_t)-1; } |
||||
|
||||
// The next 2 methods are medium-level I/O routines.
|
||||
|
||||
// ReadString returns a string which is owned by the caller! offset
|
||||
// specifies the offset that a length-encoded string is stored at in the
|
||||
// minidump file.
|
||||
string* ReadString(off_t offset); |
||||
|
||||
// SeekToStreamType positions the file at the beginning of a stream
|
||||
// identified by stream_type, and informs the caller of the stream's
|
||||
// length by setting *stream_length. Because stream_map maps each stream
|
||||
// type to only one stream in the file, this might mislead the user into
|
||||
// thinking that the stream that this seeks to is the only stream with
|
||||
// type stream_type. That can't happen for streams that these classes
|
||||
// deal with directly, because they're only supposed to be present in the
|
||||
// file singly, and that's verified when stream_map_ is built. Users who
|
||||
// are looking for other stream types should be aware of this
|
||||
// possibility, and consider using GetDirectoryEntryAtIndex (possibly
|
||||
// with GetDirectoryEntryCount) if expecting multiple streams of the same
|
||||
// type in a single minidump file.
|
||||
bool SeekToStreamType(u_int32_t stream_type, u_int32_t* stream_length); |
||||
|
||||
bool swap() const { return valid_ ? swap_ : false; } |
||||
|
||||
// Print a human-readable representation of the object to stdout.
|
||||
void Print(); |
||||
|
||||
private: |
||||
// MinidumpStreamInfo is used in the MinidumpStreamMap. It lets
|
||||
// the Minidump object locate interesting streams quickly, and
|
||||
// provides a convenient place to stash MinidumpStream objects.
|
||||
struct MinidumpStreamInfo { |
||||
MinidumpStreamInfo() : stream_index(0), stream(NULL) {} |
||||
~MinidumpStreamInfo() { delete stream; } |
||||
|
||||
// Index into the MinidumpDirectoryEntries vector
|
||||
unsigned int stream_index; |
||||
|
||||
// Pointer to the stream if cached, or NULL if not yet populated
|
||||
MinidumpStream* stream; |
||||
}; |
||||
|
||||
typedef vector<MDRawDirectory> MinidumpDirectoryEntries; |
||||
typedef map<u_int32_t, MinidumpStreamInfo> MinidumpStreamMap; |
||||
|
||||
template<typename T> T* GetStream(T** stream); |
||||
|
||||
// Opens the minidump file, or if already open, seeks to the beginning.
|
||||
bool Open(); |
||||
|
||||
// The largest number of top-level streams that will be read from a minidump.
|
||||
// Note that streams are only read (and only consume memory) as needed,
|
||||
// when directed by the caller. The default is 128.
|
||||
static u_int32_t max_streams_; |
||||
|
||||
// The maximum length of a UTF-16 string that will be read from a minidump
|
||||
// in 16-bit words. The default is 1024. UTF-16 strings are converted
|
||||
// to UTF-8 when stored in memory, and each UTF-16 word will be represented
|
||||
// by as many as 3 bytes in UTF-8.
|
||||
static unsigned int max_string_length_; |
||||
|
||||
MDRawHeader header_; |
||||
|
||||
// The list of streams.
|
||||
MinidumpDirectoryEntries* directory_; |
||||
|
||||
// Access to streams using the stream type as the key.
|
||||
MinidumpStreamMap* stream_map_; |
||||
|
||||
// The pathname of the minidump file to process, set in the constructor.
|
||||
const string path_; |
||||
|
||||
// The file descriptor for all file I/O. Used by ReadBytes and SeekSet.
|
||||
// Set based on the |path_| member by Open, which is called by Read.
|
||||
int fd_; |
||||
|
||||
// swap_ is true if the minidump file should be byte-swapped. If the
|
||||
// minidump was produced by a CPU that is other-endian than the CPU
|
||||
// processing the minidump, this will be true. If the two CPUs are
|
||||
// same-endian, this will be false.
|
||||
bool swap_; |
||||
|
||||
// Validity of the Minidump structure, false immediately after
|
||||
// construction or after a failed Read(); true following a successful
|
||||
// Read().
|
||||
bool valid_; |
||||
}; |
||||
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
|
||||
#endif // GOOGLE_BREAKPAD_PROCESSOR_MINIDUMP_H__
|
@ -0,0 +1,94 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_PROCESSOR_MINIDUMP_PROCESSOR_H__ |
||||
#define GOOGLE_BREAKPAD_PROCESSOR_MINIDUMP_PROCESSOR_H__ |
||||
|
||||
#include <string> |
||||
#include "google_breakpad/common/breakpad_types.h" |
||||
|
||||
namespace google_breakpad { |
||||
|
||||
using std::string; |
||||
|
||||
class Minidump; |
||||
class ProcessState; |
||||
class SourceLineResolverInterface; |
||||
class SymbolSupplier; |
||||
class SystemInfo; |
||||
|
||||
class MinidumpProcessor { |
||||
public: |
||||
// Return type for Process()
|
||||
enum ProcessResult { |
||||
PROCESS_OK, // the minidump was processed successfully
|
||||
PROCESS_ERROR, // there was an error processing the minidump
|
||||
PROCESS_INTERRUPTED // processing was interrupted by the SymbolSupplier
|
||||
}; |
||||
|
||||
// Initializes this MinidumpProcessor. supplier should be an
|
||||
// implementation of the SymbolSupplier abstract base class.
|
||||
MinidumpProcessor(SymbolSupplier *supplier, |
||||
SourceLineResolverInterface *resolver); |
||||
~MinidumpProcessor(); |
||||
|
||||
// Processes the minidump file and fills process_state with the result.
|
||||
ProcessResult Process(const string &minidump_file, |
||||
ProcessState *process_state); |
||||
|
||||
// Populates the cpu_* fields of the |info| parameter with textual
|
||||
// representations of the CPU type that the minidump in |dump| was
|
||||
// produced on. Returns false if this information is not available in
|
||||
// the minidump.
|
||||
static bool GetCPUInfo(Minidump *dump, SystemInfo *info); |
||||
|
||||
// Populates the os_* fields of the |info| parameter with textual
|
||||
// representations of the operating system that the minidump in |dump|
|
||||
// was produced on. Returns false if this information is not available in
|
||||
// the minidump.
|
||||
static bool GetOSInfo(Minidump *dump, SystemInfo *info); |
||||
|
||||
// Returns a textual representation of the reason that a crash occurred,
|
||||
// if the minidump in dump was produced as a result of a crash. Returns
|
||||
// an empty string if this information cannot be determined. If address
|
||||
// is non-NULL, it will be set to contain the address that caused the
|
||||
// exception, if this information is available. This will be a code
|
||||
// address when the crash was caused by problems such as illegal
|
||||
// instructions or divisions by zero, or a data address when the crash
|
||||
// was caused by a memory access violation.
|
||||
static string GetCrashReason(Minidump *dump, u_int64_t *address); |
||||
|
||||
private: |
||||
SymbolSupplier *supplier_; |
||||
SourceLineResolverInterface *resolver_; |
||||
}; |
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // GOOGLE_BREAKPAD_PROCESSOR_MINIDUMP_PROCESSOR_H__
|
@ -0,0 +1,115 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// process_state.h: A snapshot of a process, in a fully-digested state.
|
||||
//
|
||||
// Author: Mark Mentovai
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_PROCESSOR_PROCESS_STATE_H__ |
||||
#define GOOGLE_BREAKPAD_PROCESSOR_PROCESS_STATE_H__ |
||||
|
||||
#include <string> |
||||
#include <vector> |
||||
#include "google_breakpad/processor/system_info.h" |
||||
#include "google_breakpad/common/breakpad_types.h" |
||||
|
||||
namespace google_breakpad { |
||||
|
||||
using std::string; |
||||
using std::vector; |
||||
|
||||
class CallStack; |
||||
class CodeModules; |
||||
|
||||
class ProcessState { |
||||
public: |
||||
ProcessState() : modules_(NULL) { Clear(); } |
||||
~ProcessState(); |
||||
|
||||
// Resets the ProcessState to its default values
|
||||
void Clear(); |
||||
|
||||
// Accessors. See the data declarations below.
|
||||
u_int32_t time_date_stamp() const { return time_date_stamp_; } |
||||
bool crashed() const { return crashed_; } |
||||
string crash_reason() const { return crash_reason_; } |
||||
u_int64_t crash_address() const { return crash_address_; } |
||||
int requesting_thread() const { return requesting_thread_; } |
||||
const vector<CallStack*>* threads() const { return &threads_; } |
||||
const SystemInfo* system_info() const { return &system_info_; } |
||||
const CodeModules* modules() const { return modules_; } |
||||
|
||||
private: |
||||
// MinidumpProcessor is responsible for building ProcessState objects.
|
||||
friend class MinidumpProcessor; |
||||
|
||||
// The time-date stamp of the minidump (time_t format)
|
||||
u_int32_t time_date_stamp_; |
||||
|
||||
// True if the process crashed, false if the dump was produced outside
|
||||
// of an exception handler.
|
||||
bool crashed_; |
||||
|
||||
// If the process crashed, the type of crash. OS- and possibly CPU-
|
||||
// specific. For example, "EXCEPTION_ACCESS_VIOLATION" (Windows),
|
||||
// "EXC_BAD_ACCESS / KERN_INVALID_ADDRESS" (Mac OS X), "SIGSEGV"
|
||||
// (other Unix).
|
||||
string crash_reason_; |
||||
|
||||
// If the process crashed, and if crash_reason implicates memory,
|
||||
// the memory address that caused the crash. For data access errors,
|
||||
// this will be the data address that caused the fault. For code errors,
|
||||
// this will be the address of the instruction that caused the fault.
|
||||
u_int64_t crash_address_; |
||||
|
||||
// The index of the thread that requested a dump be written in the
|
||||
// threads vector. If a dump was produced as a result of a crash, this
|
||||
// will point to the thread that crashed. If the dump was produced as
|
||||
// by user code without crashing, and the dump contains extended Breakpad
|
||||
// information, this will point to the thread that requested the dump.
|
||||
// If the dump was not produced as a result of an exception and no
|
||||
// extended Breakpad information is present, this field will be set to -1,
|
||||
// indicating that the dump thread is not available.
|
||||
int requesting_thread_; |
||||
|
||||
// Stacks for each thread (except possibly the exception handler
|
||||
// thread) at the time of the crash.
|
||||
vector<CallStack*> threads_; |
||||
|
||||
// OS and CPU information.
|
||||
SystemInfo system_info_; |
||||
|
||||
// The modules that were loaded into the process represented by the
|
||||
// ProcessState.
|
||||
const CodeModules *modules_; |
||||
}; |
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // GOOGLE_BREAKPAD_PROCESSOR_PROCESS_STATE_H__
|
@ -0,0 +1,82 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Abstract interface to return function/file/line info for a memory address.
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_PROCESSOR_SOURCE_LINE_RESOLVER_INTERFACE_H__ |
||||
#define GOOGLE_BREAKPAD_PROCESSOR_SOURCE_LINE_RESOLVER_INTERFACE_H__ |
||||
|
||||
#include <string> |
||||
#include "google_breakpad/common/breakpad_types.h" |
||||
|
||||
namespace google_breakpad { |
||||
|
||||
using std::string; |
||||
|
||||
struct StackFrame; |
||||
struct StackFrameInfo; |
||||
|
||||
class SourceLineResolverInterface { |
||||
public: |
||||
typedef u_int64_t MemAddr; |
||||
|
||||
virtual ~SourceLineResolverInterface() {} |
||||
|
||||
// Adds a module to this resolver, returning true on success.
|
||||
//
|
||||
// module_name may be an arbitrary string. Typically, it will be the
|
||||
// filename of the module, optionally with version identifiers.
|
||||
//
|
||||
// map_file should contain line/address mappings for this module.
|
||||
virtual bool LoadModule(const string &module_name, |
||||
const string &map_file) = 0; |
||||
// Same as above, but takes the contents of a pre-read map buffer
|
||||
virtual bool LoadModuleUsingMapBuffer(const string &module_name, |
||||
const string &map_buffer) = 0; |
||||
|
||||
// Returns true if a module with the given name has been loaded.
|
||||
virtual bool HasModule(const string &module_name) const = 0; |
||||
|
||||
// Fills in the function_base, function_name, source_file_name,
|
||||
// and source_line fields of the StackFrame. The instruction and
|
||||
// module_name fields must already be filled in. Additional debugging
|
||||
// information, if available, is returned. If the information is not
|
||||
// available, returns NULL. A NULL return value does not indicate an
|
||||
// error. The caller takes ownership of any returned StackFrameInfo
|
||||
// object.
|
||||
virtual StackFrameInfo* FillSourceLineInfo(StackFrame *frame) const = 0; |
||||
|
||||
protected: |
||||
// SourceLineResolverInterface cannot be instantiated except by subclasses
|
||||
SourceLineResolverInterface() {} |
||||
}; |
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // GOOGLE_BREAKPAD_PROCESSOR_SOURCE_LINE_RESOLVER_INTERFACE_H__
|
@ -0,0 +1,84 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_PROCESSOR_STACK_FRAME_H__ |
||||
#define GOOGLE_BREAKPAD_PROCESSOR_STACK_FRAME_H__ |
||||
|
||||
#include <string> |
||||
#include "google_breakpad/common/breakpad_types.h" |
||||
|
||||
namespace google_breakpad { |
||||
|
||||
class CodeModule; |
||||
|
||||
using std::string; |
||||
|
||||
struct StackFrame { |
||||
StackFrame() |
||||
: instruction(), |
||||
module(NULL), |
||||
function_name(), |
||||
function_base(), |
||||
source_file_name(), |
||||
source_line(), |
||||
source_line_base() {} |
||||
virtual ~StackFrame() {} |
||||
|
||||
// The program counter location as an absolute virtual address. For the
|
||||
// innermost called frame in a stack, this will be an exact program counter
|
||||
// or instruction pointer value. For all other frames, this will be within
|
||||
// the instruction that caused execution to branch to a called function,
|
||||
// but may not necessarily point to the exact beginning of that instruction.
|
||||
u_int64_t instruction; |
||||
|
||||
// The module in which the instruction resides.
|
||||
const CodeModule *module; |
||||
|
||||
// The function name, may be omitted if debug symbols are not available.
|
||||
string function_name; |
||||
|
||||
// The start address of the function, may be omitted if debug symbols
|
||||
// are not available.
|
||||
u_int64_t function_base; |
||||
|
||||
// The source file name, may be omitted if debug symbols are not available.
|
||||
string source_file_name; |
||||
|
||||
// The (1-based) source line number, may be omitted if debug symbols are
|
||||
// not available.
|
||||
int source_line; |
||||
|
||||
// The start address of the source line, may be omitted if debug symbols
|
||||
// are not available.
|
||||
u_int64_t source_line_base; |
||||
}; |
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // GOOGLE_BREAKPAD_PROCESSOR_STACK_FRAME_H__
|
@ -0,0 +1,153 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// stack_frame_cpu.h: CPU-specific StackFrame extensions.
|
||||
//
|
||||
// These types extend the StackFrame structure to carry CPU-specific register
|
||||
// state. They are defined in this header instead of stack_frame.h to
|
||||
// avoid the need to include minidump_format.h when only the generic
|
||||
// StackFrame type is needed.
|
||||
//
|
||||
// Author: Mark Mentovai
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_PROCESSOR_STACK_FRAME_CPU_H__ |
||||
#define GOOGLE_BREAKPAD_PROCESSOR_STACK_FRAME_CPU_H__ |
||||
|
||||
#include "google_breakpad/common/minidump_format.h" |
||||
#include "google_breakpad/processor/stack_frame.h" |
||||
|
||||
namespace google_breakpad { |
||||
|
||||
struct StackFrameX86 : public StackFrame { |
||||
// ContextValidity has one entry for each relevant hardware pointer register
|
||||
// (%eip and %esp) and one entry for each nonvolatile (callee-save) register.
|
||||
enum ContextValidity { |
||||
CONTEXT_VALID_NONE = 0, |
||||
CONTEXT_VALID_EIP = 1 << 0, |
||||
CONTEXT_VALID_ESP = 1 << 1, |
||||
CONTEXT_VALID_EBP = 1 << 2, |
||||
CONTEXT_VALID_EBX = 1 << 3, |
||||
CONTEXT_VALID_ESI = 1 << 4, |
||||
CONTEXT_VALID_EDI = 1 << 5, |
||||
CONTEXT_VALID_ALL = -1 |
||||
}; |
||||
|
||||
StackFrameX86() : context(), context_validity(CONTEXT_VALID_NONE) {} |
||||
|
||||
// Register state. This is only fully valid for the topmost frame in a
|
||||
// stack. In other frames, the values of nonvolatile registers may be
|
||||
// present, given sufficient debugging information. Refer to
|
||||
// context_validity.
|
||||
MDRawContextX86 context; |
||||
|
||||
// context_validity is actually ContextValidity, but int is used because
|
||||
// the OR operator doesn't work well with enumerated types. This indicates
|
||||
// which fields in context are valid.
|
||||
int context_validity; |
||||
}; |
||||
|
||||
struct StackFramePPC : public StackFrame { |
||||
// ContextValidity should eventually contain entries for the validity of
|
||||
// other nonvolatile (callee-save) registers as in
|
||||
// StackFrameX86::ContextValidity, but the ppc stackwalker doesn't currently
|
||||
// locate registers other than the ones listed here.
|
||||
enum ContextValidity { |
||||
CONTEXT_VALID_NONE = 0, |
||||
CONTEXT_VALID_SRR0 = 1 << 0, |
||||
CONTEXT_VALID_GPR1 = 1 << 1, |
||||
CONTEXT_VALID_ALL = -1 |
||||
}; |
||||
|
||||
StackFramePPC() : context(), context_validity(CONTEXT_VALID_NONE) {} |
||||
|
||||
// Register state. This is only fully valid for the topmost frame in a
|
||||
// stack. In other frames, the values of nonvolatile registers may be
|
||||
// present, given sufficient debugging information. Refer to
|
||||
// context_validity.
|
||||
MDRawContextPPC context; |
||||
|
||||
// context_validity is actually ContextValidity, but int is used because
|
||||
// the OR operator doesn't work well with enumerated types. This indicates
|
||||
// which fields in context are valid.
|
||||
int context_validity; |
||||
}; |
||||
|
||||
struct StackFrameAMD64 : public StackFrame { |
||||
// ContextValidity has one entry for each relevant hardware pointer register
|
||||
// (%rip and %rsp) and one entry for each nonvolatile (callee-save) register.
|
||||
//FIXME: validate this list
|
||||
enum ContextValidity { |
||||
CONTEXT_VALID_NONE = 0, |
||||
CONTEXT_VALID_RIP = 1 << 0, |
||||
CONTEXT_VALID_RSP = 1 << 1, |
||||
CONTEXT_VALID_RBP = 1 << 2, |
||||
CONTEXT_VALID_ALL = -1 |
||||
}; |
||||
|
||||
StackFrameAMD64() : context(), context_validity(CONTEXT_VALID_NONE) {} |
||||
|
||||
// Register state. This is only fully valid for the topmost frame in a
|
||||
// stack. In other frames, the values of nonvolatile registers may be
|
||||
// present, given sufficient debugging information. Refer to
|
||||
// context_validity.
|
||||
MDRawContextAMD64 context; |
||||
|
||||
// context_validity is actually ContextValidity, but int is used because
|
||||
// the OR operator doesn't work well with enumerated types. This indicates
|
||||
// which fields in context are valid.
|
||||
int context_validity; |
||||
}; |
||||
|
||||
struct StackFrameSPARC : public StackFrame { |
||||
// to be confirmed
|
||||
enum ContextValidity { |
||||
CONTEXT_VALID_NONE = 0, |
||||
CONTEXT_VALID_PC = 1 << 0, |
||||
CONTEXT_VALID_SP = 1 << 1, |
||||
CONTEXT_VALID_FP = 1 << 2, |
||||
CONTEXT_VALID_ALL = -1 |
||||
}; |
||||
|
||||
StackFrameSPARC() : context(), context_validity(CONTEXT_VALID_NONE) {} |
||||
|
||||
// Register state. This is only fully valid for the topmost frame in a
|
||||
// stack. In other frames, the values of nonvolatile registers may be
|
||||
// present, given sufficient debugging information. Refer to
|
||||
// context_validity.
|
||||
MDRawContextSPARC context; |
||||
|
||||
// context_validity is actually ContextValidity, but int is used because
|
||||
// the OR operator doesn't work well with enumerated types. This indicates
|
||||
// which fields in context are valid.
|
||||
int context_validity; |
||||
}; |
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // GOOGLE_BREAKPAD_PROCESSOR_STACK_FRAME_CPU_H__
|
@ -0,0 +1,140 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// stackwalker.h: Generic stackwalker.
|
||||
//
|
||||
// The Stackwalker class is an abstract base class providing common generic
|
||||
// methods that apply to stacks from all systems. Specific implementations
|
||||
// will extend this class by providing GetContextFrame and GetCallerFrame
|
||||
// methods to fill in system-specific data in a StackFrame structure.
|
||||
// Stackwalker assembles these StackFrame strucutres into a CallStack.
|
||||
//
|
||||
// Author: Mark Mentovai
|
||||
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_PROCESSOR_STACKWALKER_H__ |
||||
#define GOOGLE_BREAKPAD_PROCESSOR_STACKWALKER_H__ |
||||
|
||||
#include <vector> |
||||
|
||||
namespace google_breakpad { |
||||
|
||||
class CallStack; |
||||
class CodeModules; |
||||
template<typename T> class linked_ptr; |
||||
class MemoryRegion; |
||||
class MinidumpContext; |
||||
class SourceLineResolverInterface; |
||||
struct StackFrame; |
||||
struct StackFrameInfo; |
||||
class SymbolSupplier; |
||||
class SystemInfo; |
||||
|
||||
using std::vector; |
||||
|
||||
|
||||
class Stackwalker { |
||||
public: |
||||
virtual ~Stackwalker() {} |
||||
|
||||
// Populates the given CallStack by calling GetContextFrame and
|
||||
// GetCallerFrame. The frames are further processed to fill all available
|
||||
// data. Returns true if the stackwalk completed, or false if it was
|
||||
// interrupted by SymbolSupplier::GetSymbolFile().
|
||||
bool Walk(CallStack *stack); |
||||
|
||||
// Returns a new concrete subclass suitable for the CPU that a stack was
|
||||
// generated on, according to the CPU type indicated by the context
|
||||
// argument. If no suitable concrete subclass exists, returns NULL.
|
||||
static Stackwalker* StackwalkerForCPU(const SystemInfo *system_info, |
||||
MinidumpContext *context, |
||||
MemoryRegion *memory, |
||||
const CodeModules *modules, |
||||
SymbolSupplier *supplier, |
||||
SourceLineResolverInterface *resolver); |
||||
|
||||
protected: |
||||
// system_info identifies the operating system, NULL or empty if unknown.
|
||||
// memory identifies a MemoryRegion that provides the stack memory
|
||||
// for the stack to walk. modules, if non-NULL, is a CodeModules
|
||||
// object that is used to look up which code module each stack frame is
|
||||
// associated with. supplier is an optional caller-supplied SymbolSupplier
|
||||
// implementation. If supplier is NULL, source line info will not be
|
||||
// resolved. resolver is an instance of SourceLineResolverInterface
|
||||
// (see source_line_resolver_interface.h and basic_source_line_resolver.h).
|
||||
// If resolver is NULL, source line info will not be resolved.
|
||||
Stackwalker(const SystemInfo *system_info, |
||||
MemoryRegion *memory, |
||||
const CodeModules *modules, |
||||
SymbolSupplier *supplier, |
||||
SourceLineResolverInterface *resolver); |
||||
|
||||
// Information about the system that produced the minidump. Subclasses
|
||||
// and the SymbolSupplier may find this information useful.
|
||||
const SystemInfo *system_info_; |
||||
|
||||
// The stack memory to walk. Subclasses will require this region to
|
||||
// get information from the stack.
|
||||
MemoryRegion *memory_; |
||||
|
||||
// A list of modules, for populating each StackFrame's module information.
|
||||
// This field is optional and may be NULL.
|
||||
const CodeModules *modules_; |
||||
|
||||
private: |
||||
// Obtains the context frame, the innermost called procedure in a stack
|
||||
// trace. Returns NULL on failure. GetContextFrame allocates a new
|
||||
// StackFrame (or StackFrame subclass), ownership of which is taken by
|
||||
// the caller.
|
||||
virtual StackFrame* GetContextFrame() = 0; |
||||
|
||||
// Obtains a caller frame. Each call to GetCallerFrame should return the
|
||||
// frame that called the last frame returned by GetContextFrame or
|
||||
// GetCallerFrame. To aid this purpose, stack contains the CallStack
|
||||
// made of frames that have already been walked. GetCallerFrame should
|
||||
// return NULL on failure or when there are no more caller frames (when
|
||||
// the end of the stack has been reached). GetCallerFrame allocates a new
|
||||
// StackFrame (or StackFrame subclass), ownership of which is taken by
|
||||
// the caller.
|
||||
virtual StackFrame* GetCallerFrame( |
||||
const CallStack *stack, |
||||
const vector< linked_ptr<StackFrameInfo> > &stack_frame_info) = 0; |
||||
|
||||
// The optional SymbolSupplier for resolving source line info.
|
||||
SymbolSupplier *supplier_; |
||||
|
||||
// The SourceLineResolver implementation
|
||||
SourceLineResolverInterface *resolver_; |
||||
}; |
||||
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
|
||||
#endif // GOOGLE_BREAKPAD_PROCESSOR_STACKWALKER_H__
|
@ -0,0 +1,82 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// The caller may implement the SymbolSupplier abstract base class
|
||||
// to provide symbols for a given module.
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_PROCESSOR_SYMBOL_SUPPLIER_H__ |
||||
#define GOOGLE_BREAKPAD_PROCESSOR_SYMBOL_SUPPLIER_H__ |
||||
|
||||
#include <string> |
||||
|
||||
namespace google_breakpad { |
||||
|
||||
using std::string; |
||||
class CodeModule; |
||||
class SystemInfo; |
||||
|
||||
class SymbolSupplier { |
||||
public: |
||||
// Result type for GetSymbolFile
|
||||
enum SymbolResult { |
||||
// no symbols were found, but continue processing
|
||||
NOT_FOUND, |
||||
|
||||
// symbols were found, and the path has been placed in symbol_file
|
||||
FOUND, |
||||
|
||||
// stops processing the minidump immediately
|
||||
INTERRUPT |
||||
}; |
||||
|
||||
virtual ~SymbolSupplier() {} |
||||
|
||||
// Retrieves the symbol file for the given CodeModule, placing the
|
||||
// path in symbol_file if successful. system_info contains strings
|
||||
// identifying the operating system and CPU; SymbolSupplier may use
|
||||
// to help locate the symbol file. system_info may be NULL or its
|
||||
// fields may be empty if these values are unknown. symbol_file
|
||||
// must be a pointer to a valid string
|
||||
virtual SymbolResult GetSymbolFile(const CodeModule *module, |
||||
const SystemInfo *system_info, |
||||
string *symbol_file) = 0; |
||||
// Same as above, except also places symbol data into symbol_data.
|
||||
// If symbol_data is NULL, the data is not returned.
|
||||
// TODO(nealsid) Once we have symbol data caching behavior implemented
|
||||
// investigate making all symbol suppliers implement all methods,
|
||||
// and make this pure virtual
|
||||
virtual SymbolResult GetSymbolFile(const CodeModule *module, |
||||
const SystemInfo *system_info, |
||||
string *symbol_file, |
||||
string *symbol_data) = 0; |
||||
}; |
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // GOOGLE_BREAKPAD_PROCESSOR_SYMBOL_SUPPLIER_H__
|
@ -0,0 +1,97 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// system_info.h: Information about the system that was running a program
|
||||
// when a crash report was produced.
|
||||
//
|
||||
// Author: Mark Mentovai
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_PROCESSOR_SYSTEM_INFO_H__ |
||||
#define GOOGLE_BREAKPAD_PROCESSOR_SYSTEM_INFO_H__ |
||||
|
||||
#include <string> |
||||
|
||||
namespace google_breakpad { |
||||
|
||||
using std::string; |
||||
|
||||
struct SystemInfo { |
||||
public: |
||||
SystemInfo() : os(), os_short(), os_version(), cpu(), cpu_info(), |
||||
cpu_count(0) {} |
||||
|
||||
// Resets the SystemInfo object to its default values.
|
||||
void Clear() { |
||||
os.clear(); |
||||
os_short.clear(); |
||||
os_version.clear(); |
||||
cpu.clear(); |
||||
cpu_info.clear(); |
||||
cpu_count = 0; |
||||
} |
||||
|
||||
// A string identifying the operating system, such as "Windows NT",
|
||||
// "Mac OS X", or "Linux". If the information is present in the dump but
|
||||
// its value is unknown, this field will contain a numeric value. If
|
||||
// the information is not present in the dump, this field will be empty.
|
||||
string os; |
||||
|
||||
// A short form of the os string, using lowercase letters and no spaces,
|
||||
// suitable for use in a filesystem. Possible values are "windows",
|
||||
// "mac", and "linux". Empty if the information is not present in the dump
|
||||
// or if the OS given by the dump is unknown. The values stored in this
|
||||
// field should match those used by MinidumpSystemInfo::GetOS.
|
||||
string os_short; |
||||
|
||||
// A string identifying the version of the operating system, such as
|
||||
// "5.1.2600 Service Pack 2" or "10.4.8 8L2127". If the dump does not
|
||||
// contain this information, this field will be empty.
|
||||
string os_version; |
||||
|
||||
// A string identifying the basic CPU family, such as "x86" or "ppc".
|
||||
// If this information is present in the dump but its value is unknown,
|
||||
// this field will contain a numeric value. If the information is not
|
||||
// present in the dump, this field will be empty. The values stored in
|
||||
// this field should match those used by MinidumpSystemInfo::GetCPU.
|
||||
string cpu; |
||||
|
||||
// A string further identifying the specific CPU, such as
|
||||
// "GenuineIntel level 6 model 13 stepping 8". If the information is not
|
||||
// present in the dump, or additional identifying information is not
|
||||
// defined for the CPU family, this field will be empty.
|
||||
string cpu_info; |
||||
|
||||
// The number of processors in the system. Will be greater than one for
|
||||
// multi-core systems.
|
||||
int cpu_count; |
||||
}; |
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // GOOGLE_BREAKPAD_PROCESSOR_SYSTEM_INFO_H__
|
@ -0,0 +1,92 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// address_map-inl.h: Address map implementation.
|
||||
//
|
||||
// See address_map.h for documentation.
|
||||
//
|
||||
// Author: Mark Mentovai
|
||||
|
||||
#ifndef PROCESSOR_ADDRESS_MAP_INL_H__ |
||||
#define PROCESSOR_ADDRESS_MAP_INL_H__ |
||||
|
||||
#include <cassert> |
||||
|
||||
#include "processor/address_map.h" |
||||
#include "processor/logging.h" |
||||
|
||||
namespace google_breakpad { |
||||
|
||||
template<typename AddressType, typename EntryType> |
||||
bool AddressMap<AddressType, EntryType>::Store(const AddressType &address, |
||||
const EntryType &entry) { |
||||
// Ensure that the specified address doesn't conflict with something already
|
||||
// in the map.
|
||||
if (map_.find(address) != map_.end()) { |
||||
BPLOG(INFO) << "Store failed, address " << HexString(address) << |
||||
" is already present"; |
||||
return false; |
||||
} |
||||
|
||||
map_.insert(MapValue(address, entry)); |
||||
return true; |
||||
} |
||||
|
||||
template<typename AddressType, typename EntryType> |
||||
bool AddressMap<AddressType, EntryType>::Retrieve( |
||||
const AddressType &address, |
||||
EntryType *entry, AddressType *entry_address) const { |
||||
BPLOG_IF(ERROR, !entry) << "AddressMap::Retrieve requires |entry|"; |
||||
assert(entry); |
||||
|
||||
// upper_bound gives the first element whose key is greater than address,
|
||||
// but we want the first element whose key is less than or equal to address.
|
||||
// Decrement the iterator to get there, but not if the upper_bound already
|
||||
// points to the beginning of the map - in that case, address is lower than
|
||||
// the lowest stored key, so return false.
|
||||
MapConstIterator iterator = map_.upper_bound(address); |
||||
if (iterator == map_.begin()) |
||||
return false; |
||||
--iterator; |
||||
|
||||
*entry = iterator->second; |
||||
if (entry_address) |
||||
*entry_address = iterator->first; |
||||
|
||||
return true; |
||||
} |
||||
|
||||
template<typename AddressType, typename EntryType> |
||||
void AddressMap<AddressType, EntryType>::Clear() { |
||||
map_.clear(); |
||||
} |
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // PROCESSOR_ADDRESS_MAP_INL_H__
|
@ -0,0 +1,80 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// address_map.h: Address maps.
|
||||
//
|
||||
// An address map contains a set of objects keyed by address. Objects are
|
||||
// retrieved from the map by returning the object with the highest key less
|
||||
// than or equal to the lookup key.
|
||||
//
|
||||
// Author: Mark Mentovai
|
||||
|
||||
#ifndef PROCESSOR_ADDRESS_MAP_H__ |
||||
#define PROCESSOR_ADDRESS_MAP_H__ |
||||
|
||||
#include <map> |
||||
|
||||
namespace google_breakpad { |
||||
|
||||
template<typename AddressType, typename EntryType> |
||||
class AddressMap { |
||||
public: |
||||
AddressMap() : map_() {} |
||||
|
||||
// Inserts an entry into the map. Returns false without storing the entry
|
||||
// if an entry is already stored in the map at the same address as specified
|
||||
// by the address argument.
|
||||
bool Store(const AddressType &address, const EntryType &entry); |
||||
|
||||
// Locates the entry stored at the highest address less than or equal to
|
||||
// the address argument. If there is no such range, returns false. The
|
||||
// entry is returned in entry, which is a required argument. If
|
||||
// entry_address is not NULL, it will be set to the address that the entry
|
||||
// was stored at.
|
||||
bool Retrieve(const AddressType &address, |
||||
EntryType *entry, AddressType *entry_address) const; |
||||
|
||||
// Empties the address map, restoring it to the same state as when it was
|
||||
// initially created.
|
||||
void Clear(); |
||||
|
||||
private: |
||||
// Convenience types.
|
||||
typedef std::map<AddressType, EntryType> AddressToEntryMap; |
||||
typedef typename AddressToEntryMap::const_iterator MapConstIterator; |
||||
typedef typename AddressToEntryMap::value_type MapValue; |
||||
|
||||
// Maps the address of each entry to an EntryType.
|
||||
AddressToEntryMap map_; |
||||
}; |
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // PROCESSOR_ADDRESS_MAP_H__
|
||||
|
@ -0,0 +1,95 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// basic_code_module.h: Carries information about code modules that are loaded
|
||||
// into a process.
|
||||
//
|
||||
// This is a basic concrete implementation of CodeModule. It cannot be
|
||||
// instantiated directly, only based on other objects that implement
|
||||
// the CodeModule interface. It exists to provide a CodeModule implementation
|
||||
// a place to store information when the life of the original object (such as
|
||||
// a MinidumpModule) cannot be guaranteed.
|
||||
//
|
||||
// Author: Mark Mentovai
|
||||
|
||||
#ifndef PROCESSOR_BASIC_CODE_MODULE_H__ |
||||
#define PROCESSOR_BASIC_CODE_MODULE_H__ |
||||
|
||||
#include <string> |
||||
|
||||
#include "google_breakpad/processor/code_module.h" |
||||
|
||||
namespace google_breakpad { |
||||
|
||||
using std::string; |
||||
|
||||
class BasicCodeModule : public CodeModule { |
||||
public: |
||||
// Creates a new BasicCodeModule given any existing CodeModule
|
||||
// implementation. This is useful to make a copy of the data relevant to
|
||||
// the CodeModule interface without requiring all of the resources that
|
||||
// other CodeModule implementations may require.
|
||||
explicit BasicCodeModule(const CodeModule *that) |
||||
: base_address_(that->base_address()), |
||||
size_(that->size()), |
||||
code_file_(that->code_file()), |
||||
code_identifier_(that->code_identifier()), |
||||
debug_file_(that->debug_file()), |
||||
debug_identifier_(that->debug_identifier()), |
||||
version_(that->version()) {} |
||||
virtual ~BasicCodeModule() {} |
||||
|
||||
// See code_module.h for descriptions of these methods and the associated
|
||||
// members.
|
||||
virtual u_int64_t base_address() const { return base_address_; } |
||||
virtual u_int64_t size() const { return size_; } |
||||
virtual string code_file() const { return code_file_; } |
||||
virtual string code_identifier() const { return code_identifier_; } |
||||
virtual string debug_file() const { return debug_file_; } |
||||
virtual string debug_identifier() const { return debug_identifier_; } |
||||
virtual string version() const { return version_; } |
||||
virtual const CodeModule* Copy() const { return new BasicCodeModule(this); } |
||||
|
||||
private: |
||||
u_int64_t base_address_; |
||||
u_int64_t size_; |
||||
string code_file_; |
||||
string code_identifier_; |
||||
string debug_file_; |
||||
string debug_identifier_; |
||||
string version_; |
||||
|
||||
// Disallow copy constructor and assignment operator.
|
||||
BasicCodeModule(const BasicCodeModule &that); |
||||
void operator=(const BasicCodeModule &that); |
||||
}; |
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // PROCESSOR_BASIC_CODE_MODULE_H__
|
@ -0,0 +1,85 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// basic_code_modules.h: Contains all of the CodeModule objects that
|
||||
// were loaded into a single process.
|
||||
//
|
||||
// This is a basic concrete implementation of CodeModules. It cannot be
|
||||
// instantiated directly, only based on other objects that implement
|
||||
// the CodeModules interface. It exists to provide a CodeModules
|
||||
// implementation a place to store information when the life of the original
|
||||
// object (such as a MinidumpModuleList) cannot be guaranteed.
|
||||
//
|
||||
// Author: Mark Mentovai
|
||||
|
||||
#ifndef PROCESSOR_BASIC_CODE_MODULES_H__ |
||||
#define PROCESSOR_BASIC_CODE_MODULES_H__ |
||||
|
||||
#include "google_breakpad/processor/code_modules.h" |
||||
|
||||
namespace google_breakpad { |
||||
|
||||
template<typename T> class linked_ptr; |
||||
template<typename AddressType, typename EntryType> class RangeMap; |
||||
|
||||
class BasicCodeModules : public CodeModules { |
||||
public: |
||||
// Creates a new BasicCodeModules object given any existing CodeModules
|
||||
// implementation. This is useful to make a copy of the data relevant to
|
||||
// the CodeModules and CodeModule interfaces without requiring all of the
|
||||
// resources that other implementations may require. A copy will be
|
||||
// made of each contained CodeModule using CodeModule::Copy.
|
||||
explicit BasicCodeModules(const CodeModules *that); |
||||
|
||||
virtual ~BasicCodeModules(); |
||||
|
||||
// See code_modules.h for descriptions of these methods.
|
||||
virtual unsigned int module_count() const; |
||||
virtual const CodeModule* GetModuleForAddress(u_int64_t address) const; |
||||
virtual const CodeModule* GetMainModule() const; |
||||
virtual const CodeModule* GetModuleAtSequence(unsigned int sequence) const; |
||||
virtual const CodeModule* GetModuleAtIndex(unsigned int index) const; |
||||
virtual const CodeModules* Copy() const; |
||||
|
||||
private: |
||||
// The base address of the main module.
|
||||
u_int64_t main_address_; |
||||
|
||||
// The map used to contain each CodeModule, keyed by each CodeModule's
|
||||
// address range.
|
||||
RangeMap<u_int64_t, linked_ptr<const CodeModule> > *map_; |
||||
|
||||
// Disallow copy constructor and assignment operator.
|
||||
BasicCodeModules(const BasicCodeModules &that); |
||||
void operator=(const BasicCodeModules &that); |
||||
}; |
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // PROCESSOR_BASIC_CODE_MODULES_H__
|
@ -0,0 +1,197 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// contained_range_map-inl.h: Hierarchically-organized range map implementation.
|
||||
//
|
||||
// See contained_range_map.h for documentation.
|
||||
//
|
||||
// Author: Mark Mentovai
|
||||
|
||||
#ifndef PROCESSOR_CONTAINED_RANGE_MAP_INL_H__ |
||||
#define PROCESSOR_CONTAINED_RANGE_MAP_INL_H__ |
||||
|
||||
|
||||
#include <cassert> |
||||
|
||||
#include "processor/contained_range_map.h" |
||||
#include "processor/logging.h" |
||||
|
||||
|
||||
namespace google_breakpad { |
||||
|
||||
|
||||
template<typename AddressType, typename EntryType> |
||||
ContainedRangeMap<AddressType, EntryType>::~ContainedRangeMap() { |
||||
// Clear frees the children pointed to by the map, and frees the map itself.
|
||||
Clear(); |
||||
} |
||||
|
||||
|
||||
template<typename AddressType, typename EntryType> |
||||
bool ContainedRangeMap<AddressType, EntryType>::StoreRange( |
||||
const AddressType &base, const AddressType &size, const EntryType &entry) { |
||||
AddressType high = base + size - 1; |
||||
|
||||
// Check for undersize or overflow.
|
||||
if (size <= 0 || high < base) { |
||||
//TODO(nealsid) We are commenting this out in order to prevent
|
||||
// excessive logging. We plan to move to better logging as this
|
||||
// failure happens quite often and is expected(see comment in
|
||||
// basic_source_line_resolver.cc:671).
|
||||
// BPLOG(INFO) << "StoreRange failed, " << HexString(base) << "+"
|
||||
// << HexString(size) << ", " << HexString(high);
|
||||
return false; |
||||
} |
||||
|
||||
if (!map_) |
||||
map_ = new AddressToRangeMap(); |
||||
|
||||
MapIterator iterator_base = map_->lower_bound(base); |
||||
MapIterator iterator_high = map_->lower_bound(high); |
||||
MapIterator iterator_end = map_->end(); |
||||
|
||||
if (iterator_base == iterator_high && iterator_base != iterator_end && |
||||
base >= iterator_base->second->base_) { |
||||
// The new range is entirely within an existing child range.
|
||||
|
||||
// If the new range's geometry is exactly equal to an existing child
|
||||
// range's, it violates the containment rules, and an attempt to store
|
||||
// it must fail. iterator_base->first contains the key, which was the
|
||||
// containing child's high address.
|
||||
if (iterator_base->second->base_ == base && iterator_base->first == high) { |
||||
// TODO(nealsid): See the TODO above on why this is commented out.
|
||||
// BPLOG(INFO) << "StoreRange failed, identical range is already "
|
||||
// "present: " << HexString(base) << "+" << HexString(size);
|
||||
return false; |
||||
} |
||||
|
||||
// Pass the new range on to the child to attempt to store.
|
||||
return iterator_base->second->StoreRange(base, size, entry); |
||||
} |
||||
|
||||
// iterator_high might refer to an irrelevant range: one whose base address
|
||||
// is higher than the new range's high address. Set contains_high to true
|
||||
// only if iterator_high refers to a range that is at least partially
|
||||
// within the new range.
|
||||
bool contains_high = iterator_high != iterator_end && |
||||
high >= iterator_high->second->base_; |
||||
|
||||
// If the new range encompasses any existing child ranges, it must do so
|
||||
// fully. Partial containment isn't allowed.
|
||||
if ((iterator_base != iterator_end && base > iterator_base->second->base_) || |
||||
(contains_high && high < iterator_high->first)) { |
||||
// TODO(mmentovai): Some symbol files will trip this check frequently
|
||||
// on STACK lines. Too many messages will be produced. These are more
|
||||
// suitable for a DEBUG channel than an INFO channel.
|
||||
// BPLOG(INFO) << "StoreRange failed, new range partially contains "
|
||||
// "existing range: " << HexString(base) << "+" <<
|
||||
// HexString(size);
|
||||
return false; |
||||
} |
||||
|
||||
// When copying and erasing contained ranges, the "end" iterator needs to
|
||||
// point one past the last item of the range to copy. If contains_high is
|
||||
// false, the iterator's already in the right place; the increment is safe
|
||||
// because contains_high can't be true if iterator_high == iterator_end.
|
||||
if (contains_high) |
||||
++iterator_high; |
||||
|
||||
// Optimization: if the iterators are equal, no child ranges would be
|
||||
// moved. Create the new child range with a NULL map to conserve space
|
||||
// in leaf nodes, of which there will be many.
|
||||
AddressToRangeMap *child_map = NULL; |
||||
|
||||
if (iterator_base != iterator_high) { |
||||
// The children of this range that are contained by the new range must
|
||||
// be transferred over to the new range. Create the new child range map
|
||||
// and copy the pointers to range maps it should contain into it.
|
||||
child_map = new AddressToRangeMap(iterator_base, iterator_high); |
||||
|
||||
// Remove the copied child pointers from this range's map of children.
|
||||
map_->erase(iterator_base, iterator_high); |
||||
} |
||||
|
||||
// Store the new range in the map by its high address. Any children that
|
||||
// the new child range contains were formerly children of this range but
|
||||
// are now this range's grandchildren. Ownership of these is transferred
|
||||
// to the new child range.
|
||||
map_->insert(MapValue(high, |
||||
new ContainedRangeMap(base, entry, child_map))); |
||||
return true; |
||||
} |
||||
|
||||
|
||||
template<typename AddressType, typename EntryType> |
||||
bool ContainedRangeMap<AddressType, EntryType>::RetrieveRange( |
||||
const AddressType &address, EntryType *entry) const { |
||||
BPLOG_IF(ERROR, !entry) << "ContainedRangeMap::RetrieveRange requires " |
||||
"|entry|"; |
||||
assert(entry); |
||||
|
||||
// If nothing was ever stored, then there's nothing to retrieve.
|
||||
if (!map_) |
||||
return false; |
||||
|
||||
// Get an iterator to the child range whose high address is equal to or
|
||||
// greater than the supplied address. If the supplied address is higher
|
||||
// than all of the high addresses in the range, then this range does not
|
||||
// contain a child at address, so return false. If the supplied address
|
||||
// is lower than the base address of the child range, then it is not within
|
||||
// the child range, so return false.
|
||||
MapConstIterator iterator = map_->lower_bound(address); |
||||
if (iterator == map_->end() || address < iterator->second->base_) |
||||
return false; |
||||
|
||||
// The child in iterator->second contains the specified address. Find out
|
||||
// if it has a more-specific descendant that also contains it. If it does,
|
||||
// it will set |entry| appropriately. If not, set |entry| to the child.
|
||||
if (!iterator->second->RetrieveRange(address, entry)) |
||||
*entry = iterator->second->entry_; |
||||
|
||||
return true; |
||||
} |
||||
|
||||
|
||||
template<typename AddressType, typename EntryType> |
||||
void ContainedRangeMap<AddressType, EntryType>::Clear() { |
||||
if (map_) { |
||||
MapConstIterator end = map_->end(); |
||||
for (MapConstIterator child = map_->begin(); child != end; ++child) |
||||
delete child->second; |
||||
|
||||
delete map_; |
||||
map_ = NULL; |
||||
} |
||||
} |
||||
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
|
||||
#endif // PROCESSOR_CONTAINED_RANGE_MAP_INL_H__
|
@ -0,0 +1,145 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// contained_range_map.h: Hierarchically-organized range maps.
|
||||
//
|
||||
// A contained range map is similar to a standard range map, except it allows
|
||||
// objects to be organized hierarchically. A contained range map allows
|
||||
// objects to contain other objects. It is not sensitive to the order that
|
||||
// objects are added to the map: larger, more general, containing objects
|
||||
// may be added either before or after smaller, more specific, contained
|
||||
// ones.
|
||||
//
|
||||
// Contained range maps guarantee that each object may only contain smaller
|
||||
// objects than itself, and that a parent object may only contain child
|
||||
// objects located entirely within the parent's address space. Attempts
|
||||
// to introduce objects (via StoreRange) that violate these rules will fail.
|
||||
// Retrieval (via RetrieveRange) always returns the most specific (smallest)
|
||||
// object that contains the address being queried. Note that while it is
|
||||
// not possible to insert two objects into a map that have exactly the same
|
||||
// geometry (base address and size), it is possible to completely mask a
|
||||
// larger object by inserting smaller objects that entirely fill the larger
|
||||
// object's address space.
|
||||
//
|
||||
// Internally, contained range maps are implemented as a tree. Each tree
|
||||
// node except for the root node describes an object in the map. Each node
|
||||
// maintains its list of children in a map similar to a standard range map,
|
||||
// keyed by the highest address that each child occupies. Each node's
|
||||
// children occupy address ranges entirely within the node. The root node
|
||||
// is the only node directly accessible to the user, and represents the
|
||||
// entire address space.
|
||||
//
|
||||
// Author: Mark Mentovai
|
||||
|
||||
#ifndef PROCESSOR_CONTAINED_RANGE_MAP_H__ |
||||
#define PROCESSOR_CONTAINED_RANGE_MAP_H__ |
||||
|
||||
|
||||
#include <map> |
||||
|
||||
|
||||
namespace google_breakpad { |
||||
|
||||
|
||||
template<typename AddressType, typename EntryType> |
||||
class ContainedRangeMap { |
||||
public: |
||||
// The default constructor creates a ContainedRangeMap with no geometry
|
||||
// and no entry, and as such is only suitable for the root node of a
|
||||
// ContainedRangeMap tree.
|
||||
ContainedRangeMap() : base_(), entry_(), map_(NULL) {} |
||||
|
||||
~ContainedRangeMap(); |
||||
|
||||
// Inserts a range into the map. If the new range is encompassed by
|
||||
// an existing child range, the new range is passed into the child range's
|
||||
// StoreRange method. If the new range encompasses any existing child
|
||||
// ranges, those child ranges are moved to the new range, becoming
|
||||
// grandchildren of this ContainedRangeMap. Returns false for a
|
||||
// parameter error, or if the ContainedRangeMap hierarchy guarantees
|
||||
// would be violated.
|
||||
bool StoreRange(const AddressType &base, |
||||
const AddressType &size, |
||||
const EntryType &entry); |
||||
|
||||
// Retrieves the most specific (smallest) descendant range encompassing
|
||||
// the specified address. This method will only return entries held by
|
||||
// child ranges, and not the entry contained by |this|. This is necessary
|
||||
// to support a sparsely-populated root range. If no descendant range
|
||||
// encompasses the address, returns false.
|
||||
bool RetrieveRange(const AddressType &address, EntryType *entry) const; |
||||
|
||||
// Removes all children. Note that Clear only removes descendants,
|
||||
// leaving the node on which it is called intact. Because the only
|
||||
// meaningful things contained by a root node are descendants, this
|
||||
// is sufficient to restore an entire ContainedRangeMap to its initial
|
||||
// empty state when called on the root node.
|
||||
void Clear(); |
||||
|
||||
private: |
||||
// AddressToRangeMap stores pointers. This makes reparenting simpler in
|
||||
// StoreRange, because it doesn't need to copy entire objects.
|
||||
typedef std::map<AddressType, ContainedRangeMap *> AddressToRangeMap; |
||||
typedef typename AddressToRangeMap::const_iterator MapConstIterator; |
||||
typedef typename AddressToRangeMap::iterator MapIterator; |
||||
typedef typename AddressToRangeMap::value_type MapValue; |
||||
|
||||
// Creates a new ContainedRangeMap with the specified base address, entry,
|
||||
// and initial child map, which may be NULL. This is only used internally
|
||||
// by ContainedRangeMap when it creates a new child.
|
||||
ContainedRangeMap(const AddressType &base, const EntryType &entry, |
||||
AddressToRangeMap *map) |
||||
: base_(base), entry_(entry), map_(map) {} |
||||
|
||||
// The base address of this range. The high address does not need to
|
||||
// be stored, because it is used as the key to an object in its parent's
|
||||
// map, and all ContainedRangeMaps except for the root range are contained
|
||||
// within maps. The root range does not actually contain an entry, so its
|
||||
// base_ field is meaningless, and the fact that it has no parent and thus
|
||||
// no key is unimportant. For this reason, the base_ field should only be
|
||||
// is accessed on child ContainedRangeMap objects, and never on |this|.
|
||||
const AddressType base_; |
||||
|
||||
// The entry corresponding to this range. The root range does not
|
||||
// actually contain an entry, so its entry_ field is meaningless. For
|
||||
// this reason, the entry_ field should only be accessed on child
|
||||
// ContainedRangeMap objects, and never on |this|.
|
||||
const EntryType entry_; |
||||
|
||||
// The map containing child ranges, keyed by each child range's high
|
||||
// address. This is a pointer to avoid allocating map structures for
|
||||
// leaf nodes, where they are not needed.
|
||||
AddressToRangeMap *map_; |
||||
}; |
||||
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
|
||||
#endif // PROCESSOR_CONTAINED_RANGE_MAP_H__
|
@ -0,0 +1,193 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// A "smart" pointer type with reference tracking. Every pointer to a
|
||||
// particular object is kept on a circular linked list. When the last pointer
|
||||
// to an object is destroyed or reassigned, the object is deleted.
|
||||
//
|
||||
// Used properly, this deletes the object when the last reference goes away.
|
||||
// There are several caveats:
|
||||
// - Like all reference counting schemes, cycles lead to leaks.
|
||||
// - Each smart pointer is actually two pointers (8 bytes instead of 4).
|
||||
// - Every time a pointer is assigned, the entire list of pointers to that
|
||||
// object is traversed. This class is therefore NOT SUITABLE when there
|
||||
// will often be more than two or three pointers to a particular object.
|
||||
// - References are only tracked as long as linked_ptr<> objects are copied.
|
||||
// If a linked_ptr<> is converted to a raw pointer and back, BAD THINGS
|
||||
// will happen (double deletion).
|
||||
//
|
||||
// A good use of this class is storing object references in STL containers.
|
||||
// You can safely put linked_ptr<> in a vector<>.
|
||||
// Other uses may not be as good.
|
||||
//
|
||||
// Note: If you use an incomplete type with linked_ptr<>, the class
|
||||
// *containing* linked_ptr<> must have a constructor and destructor (even
|
||||
// if they do nothing!).
|
||||
|
||||
#ifndef PROCESSOR_LINKED_PTR_H__ |
||||
#define PROCESSOR_LINKED_PTR_H__ |
||||
|
||||
namespace google_breakpad { |
||||
|
||||
// This is used internally by all instances of linked_ptr<>. It needs to be
|
||||
// a non-template class because different types of linked_ptr<> can refer to
|
||||
// the same object (linked_ptr<Superclass>(obj) vs linked_ptr<Subclass>(obj)).
|
||||
// So, it needs to be possible for different types of linked_ptr to participate
|
||||
// in the same circular linked list, so we need a single class type here.
|
||||
//
|
||||
// DO NOT USE THIS CLASS DIRECTLY YOURSELF. Use linked_ptr<T>.
|
||||
class linked_ptr_internal { |
||||
public: |
||||
// Create a new circle that includes only this instance.
|
||||
void join_new() { |
||||
next_ = this; |
||||
} |
||||
|
||||
// Join an existing circle.
|
||||
void join(linked_ptr_internal const* ptr) { |
||||
linked_ptr_internal const* p = ptr; |
||||
while (p->next_ != ptr) p = p->next_; |
||||
p->next_ = this; |
||||
next_ = ptr; |
||||
} |
||||
|
||||
// Leave whatever circle we're part of. Returns true iff we were the
|
||||
// last member of the circle. Once this is done, you can join() another.
|
||||
bool depart() { |
||||
if (next_ == this) return true; |
||||
linked_ptr_internal const* p = next_; |
||||
while (p->next_ != this) p = p->next_; |
||||
p->next_ = next_; |
||||
return false; |
||||
} |
||||
|
||||
private: |
||||
mutable linked_ptr_internal const* next_; |
||||
}; |
||||
|
||||
template <typename T> |
||||
class linked_ptr { |
||||
public: |
||||
typedef T element_type; |
||||
|
||||
// Take over ownership of a raw pointer. This should happen as soon as
|
||||
// possible after the object is created.
|
||||
explicit linked_ptr(T* ptr = NULL) { capture(ptr); } |
||||
~linked_ptr() { depart(); } |
||||
|
||||
// Copy an existing linked_ptr<>, adding ourselves to the list of references.
|
||||
template <typename U> linked_ptr(linked_ptr<U> const& ptr) { copy(&ptr); } |
||||
linked_ptr(linked_ptr const& ptr) { copy(&ptr); } |
||||
|
||||
// Assignment releases the old value and acquires the new.
|
||||
template <typename U> linked_ptr& operator=(linked_ptr<U> const& ptr) { |
||||
depart(); |
||||
copy(&ptr); |
||||
return *this; |
||||
} |
||||
|
||||
linked_ptr& operator=(linked_ptr const& ptr) { |
||||
if (&ptr != this) { |
||||
depart(); |
||||
copy(&ptr); |
||||
} |
||||
return *this; |
||||
} |
||||
|
||||
// Smart pointer members.
|
||||
void reset(T* ptr = NULL) { depart(); capture(ptr); } |
||||
T* get() const { return value_; } |
||||
T* operator->() const { return value_; } |
||||
T& operator*() const { return *value_; } |
||||
// Release ownership of the pointed object and returns it.
|
||||
// Sole ownership by this linked_ptr object is required.
|
||||
T* release() { |
||||
bool last = link_.depart(); |
||||
T* v = value_; |
||||
value_ = NULL; |
||||
return v; |
||||
} |
||||
|
||||
bool operator==(T* p) const { return value_ == p; } |
||||
bool operator!=(T* p) const { return value_ != p; } |
||||
template <typename U> |
||||
bool operator==(linked_ptr<U> const& ptr) const { |
||||
return value_ == ptr.get(); |
||||
} |
||||
template <typename U> |
||||
bool operator!=(linked_ptr<U> const& ptr) const { |
||||
return value_ != ptr.get(); |
||||
} |
||||
|
||||
private: |
||||
template <typename U> |
||||
friend class linked_ptr; |
||||
|
||||
T* value_; |
||||
linked_ptr_internal link_; |
||||
|
||||
void depart() { |
||||
if (link_.depart()) delete value_; |
||||
} |
||||
|
||||
void capture(T* ptr) { |
||||
value_ = ptr; |
||||
link_.join_new(); |
||||
} |
||||
|
||||
template <typename U> void copy(linked_ptr<U> const* ptr) { |
||||
value_ = ptr->get(); |
||||
if (value_) |
||||
link_.join(&ptr->link_); |
||||
else |
||||
link_.join_new(); |
||||
} |
||||
}; |
||||
|
||||
template<typename T> inline |
||||
bool operator==(T* ptr, const linked_ptr<T>& x) { |
||||
return ptr == x.get(); |
||||
} |
||||
|
||||
template<typename T> inline |
||||
bool operator!=(T* ptr, const linked_ptr<T>& x) { |
||||
return ptr != x.get(); |
||||
} |
||||
|
||||
// A function to convert T* into linked_ptr<T>
|
||||
// Doing e.g. make_linked_ptr(new FooBarBaz<type>(arg)) is a shorter notation
|
||||
// for linked_ptr<FooBarBaz<type> >(new FooBarBaz<type>(arg))
|
||||
template <typename T> |
||||
linked_ptr<T> make_linked_ptr(T* ptr) { |
||||
return linked_ptr<T>(ptr); |
||||
} |
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // PROCESSOR_LINKED_PTR_H__
|
@ -0,0 +1,153 @@ |
||||
// Copyright (c) 2007, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// logging.h: Breakpad logging
|
||||
//
|
||||
// Breakpad itself uses Breakpad logging with statements of the form:
|
||||
// BPLOG(severity) << "message";
|
||||
// severity may be INFO, ERROR, or other values defined in this file.
|
||||
//
|
||||
// BPLOG is an overridable macro so that users can customize Breakpad's
|
||||
// logging. Left at the default, logging messages are sent to stderr along
|
||||
// with a timestamp and the source code location that produced a message.
|
||||
// The streams may be changed by redefining BPLOG_*_STREAM, the logging
|
||||
// behavior may be changed by redefining BPLOG_*, and the entire logging
|
||||
// system may be overridden by redefining BPLOG(severity). These
|
||||
// redefinitions may be passed to the preprocessor as a command-line flag
|
||||
// (-D).
|
||||
//
|
||||
// If an additional header is required to override Breakpad logging, it can
|
||||
// be specified by the BP_LOGGING_INCLUDE macro. If defined, this header
|
||||
// will #include the header specified by that macro.
|
||||
//
|
||||
// If any initialization is needed before logging, it can be performed by
|
||||
// a function called through the BPLOG_INIT macro. Each main function of
|
||||
// an executable program in the Breakpad processor library calls
|
||||
// BPLOG_INIT(&argc, &argv); before any logging can be performed; define
|
||||
// BPLOG_INIT appropriately if initialization is required.
|
||||
//
|
||||
// Author: Mark Mentovai
|
||||
|
||||
#ifndef PROCESSOR_LOGGING_H__ |
||||
#define PROCESSOR_LOGGING_H__ |
||||
|
||||
#include <iostream> |
||||
#include <string> |
||||
|
||||
#include "google_breakpad/common/breakpad_types.h" |
||||
|
||||
#ifdef BP_LOGGING_INCLUDE |
||||
#include BP_LOGGING_INCLUDE |
||||
#endif // BP_LOGGING_INCLUDE
|
||||
|
||||
namespace google_breakpad { |
||||
|
||||
class LogStream { |
||||
public: |
||||
enum Severity { |
||||
SEVERITY_INFO, |
||||
SEVERITY_ERROR |
||||
}; |
||||
|
||||
// Begin logging a message to the stream identified by |stream|, at the
|
||||
// indicated severity. The file and line parameters should be set so as to
|
||||
// identify the line of source code that is producing a message.
|
||||
LogStream(std::ostream &stream, Severity severity, |
||||
const char *file, int line); |
||||
|
||||
// Finish logging by printing a newline and flushing the output stream.
|
||||
~LogStream(); |
||||
|
||||
template<typename T> std::ostream& operator<<(const T &t) { |
||||
return stream_ << t; |
||||
} |
||||
|
||||
private: |
||||
std::ostream &stream_; |
||||
|
||||
// Disallow copy constructor and assignment operator
|
||||
explicit LogStream(const LogStream &that); |
||||
void operator=(const LogStream &that); |
||||
}; |
||||
|
||||
// This class is used to explicitly ignore values in the conditional logging
|
||||
// macros. This avoids compiler warnings like "value computed is not used"
|
||||
// and "statement has no effect".
|
||||
class LogMessageVoidify { |
||||
public: |
||||
LogMessageVoidify() {} |
||||
|
||||
// This has to be an operator with a precedence lower than << but higher
|
||||
// than ?:
|
||||
void operator&(std::ostream &) {} |
||||
}; |
||||
|
||||
// Returns number formatted as a hexadecimal string, such as "0x7b".
|
||||
std::string HexString(u_int32_t number); |
||||
std::string HexString(u_int64_t number); |
||||
std::string HexString(int number); |
||||
|
||||
// Returns the error code as set in the global errno variable, and sets
|
||||
// error_string, a required argument, to a string describing that error
|
||||
// code.
|
||||
int ErrnoString(std::string *error_string); |
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#ifndef BPLOG_INIT |
||||
#define BPLOG_INIT(pargc, pargv) |
||||
#endif // BPLOG_INIT
|
||||
|
||||
#ifndef BPLOG |
||||
#define BPLOG(severity) BPLOG_ ## severity |
||||
#endif // BPLOG
|
||||
|
||||
#ifndef BPLOG_INFO |
||||
#ifndef BPLOG_INFO_STREAM |
||||
#define BPLOG_INFO_STREAM std::clog |
||||
#endif // BPLOG_INFO_STREAM
|
||||
#define BPLOG_INFO google_breakpad::LogStream(BPLOG_INFO_STREAM, \ |
||||
google_breakpad::LogStream::SEVERITY_INFO, \
|
||||
__FILE__, __LINE__) |
||||
#endif // BPLOG_INFO
|
||||
|
||||
#ifndef BPLOG_ERROR |
||||
#ifndef BPLOG_ERROR_STREAM |
||||
#define BPLOG_ERROR_STREAM std::cerr |
||||
#endif // BPLOG_ERROR_STREAM
|
||||
#define BPLOG_ERROR google_breakpad::LogStream(BPLOG_ERROR_STREAM, \ |
||||
google_breakpad::LogStream::SEVERITY_ERROR, \
|
||||
__FILE__, __LINE__) |
||||
#endif // BPLOG_ERROR
|
||||
|
||||
#define BPLOG_IF(severity, condition) \ |
||||
!(condition) ? (void) 0 : \
|
||||
google_breakpad::LogMessageVoidify() & BPLOG(severity) |
||||
|
||||
#endif // PROCESSOR_LOGGING_H__
|
@ -0,0 +1,53 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// pathname_stripper.h: Manipulates pathnames into their component parts.
|
||||
//
|
||||
// Author: Mark Mentovai
|
||||
|
||||
#ifndef PROCESSOR_PATHNAME_STRIPPER_H__ |
||||
#define PROCESSOR_PATHNAME_STRIPPER_H__ |
||||
|
||||
#include <string> |
||||
|
||||
namespace google_breakpad { |
||||
|
||||
using std::string; |
||||
|
||||
class PathnameStripper { |
||||
public: |
||||
// Given path, a pathname with components separated by slashes (/) or
|
||||
// backslashes (\), returns the trailing component, without any separator.
|
||||
// If path ends in a separator character, returns an empty string.
|
||||
static string File(const string &path); |
||||
}; |
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // PROCESSOR_PATHNAME_STRIPPER_H__
|
@ -0,0 +1,282 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// postfix_evaluator-inl.h: Postfix (reverse Polish) notation expression
|
||||
// evaluator.
|
||||
//
|
||||
// Documentation in postfix_evaluator.h.
|
||||
//
|
||||
// Author: Mark Mentovai
|
||||
|
||||
#ifndef PROCESSOR_POSTFIX_EVALUATOR_INL_H__ |
||||
#define PROCESSOR_POSTFIX_EVALUATOR_INL_H__ |
||||
|
||||
|
||||
#include <sstream> |
||||
|
||||
#include "processor/postfix_evaluator.h" |
||||
#include "google_breakpad/processor/memory_region.h" |
||||
#include "processor/logging.h" |
||||
|
||||
namespace google_breakpad { |
||||
|
||||
using std::istringstream; |
||||
using std::ostringstream; |
||||
|
||||
|
||||
// A small class used in Evaluate to make sure to clean up the stack
|
||||
// before returning failure.
|
||||
class AutoStackClearer { |
||||
public: |
||||
explicit AutoStackClearer(vector<string> *stack) : stack_(stack) {} |
||||
~AutoStackClearer() { stack_->clear(); } |
||||
|
||||
private: |
||||
vector<string> *stack_; |
||||
}; |
||||
|
||||
|
||||
template<typename ValueType> |
||||
bool PostfixEvaluator<ValueType>::Evaluate(const string &expression, |
||||
DictionaryValidityType *assigned) { |
||||
// Ensure that the stack is cleared before returning.
|
||||
AutoStackClearer clearer(&stack_); |
||||
|
||||
// Tokenize, splitting on whitespace.
|
||||
istringstream stream(expression); |
||||
string token; |
||||
while (stream >> token) { |
||||
// There are enough binary operations that do exactly the same thing
|
||||
// (other than the specific operation, of course) that it makes sense
|
||||
// to share as much code as possible.
|
||||
enum BinaryOperation { |
||||
BINARY_OP_NONE = 0, |
||||
BINARY_OP_ADD, |
||||
BINARY_OP_SUBTRACT, |
||||
BINARY_OP_MULTIPLY, |
||||
BINARY_OP_DIVIDE_QUOTIENT, |
||||
BINARY_OP_DIVIDE_MODULUS |
||||
}; |
||||
|
||||
BinaryOperation operation = BINARY_OP_NONE; |
||||
if (token == "+") |
||||
operation = BINARY_OP_ADD; |
||||
else if (token == "-") |
||||
operation = BINARY_OP_SUBTRACT; |
||||
else if (token == "*") |
||||
operation = BINARY_OP_MULTIPLY; |
||||
else if (token == "/") |
||||
operation = BINARY_OP_DIVIDE_QUOTIENT; |
||||
else if (token == "%") |
||||
operation = BINARY_OP_DIVIDE_MODULUS; |
||||
|
||||
if (operation != BINARY_OP_NONE) { |
||||
// Get the operands.
|
||||
ValueType operand1, operand2; |
||||
if (!PopValues(&operand1, &operand2)) { |
||||
BPLOG(ERROR) << "Could not PopValues to get two values for binary " |
||||
"operation " << token << ": " << expression; |
||||
return false; |
||||
} |
||||
|
||||
// Perform the operation.
|
||||
ValueType result; |
||||
switch (operation) { |
||||
case BINARY_OP_ADD: |
||||
result = operand1 + operand2; |
||||
break; |
||||
case BINARY_OP_SUBTRACT: |
||||
result = operand1 - operand2; |
||||
break; |
||||
case BINARY_OP_MULTIPLY: |
||||
result = operand1 * operand2; |
||||
break; |
||||
case BINARY_OP_DIVIDE_QUOTIENT: |
||||
result = operand1 / operand2; |
||||
break; |
||||
case BINARY_OP_DIVIDE_MODULUS: |
||||
result = operand1 % operand2; |
||||
break; |
||||
case BINARY_OP_NONE: |
||||
// This will not happen, but compilers will want a default or
|
||||
// BINARY_OP_NONE case.
|
||||
BPLOG(ERROR) << "Not reached!"; |
||||
return false; |
||||
break; |
||||
} |
||||
|
||||
// Save the result.
|
||||
PushValue(result); |
||||
} else if (token == "^") { |
||||
// ^ for unary dereference. Can't dereference without memory.
|
||||
if (!memory_) { |
||||
BPLOG(ERROR) << "Attempt to dereference without memory: " << |
||||
expression; |
||||
return false; |
||||
} |
||||
|
||||
ValueType address; |
||||
if (!PopValue(&address)) { |
||||
BPLOG(ERROR) << "Could not PopValue to get value to derefence: " << |
||||
expression; |
||||
return false; |
||||
} |
||||
|
||||
ValueType value; |
||||
if (!memory_->GetMemoryAtAddress(address, &value)) { |
||||
BPLOG(ERROR) << "Could not dereference memory at address " << |
||||
HexString(address) << ": " << expression; |
||||
return false; |
||||
} |
||||
|
||||
PushValue(value); |
||||
} else if (token == "=") { |
||||
// = for assignment.
|
||||
ValueType value; |
||||
if (!PopValue(&value)) { |
||||
BPLOG(ERROR) << "Could not PopValue to get value to assign: " << |
||||
expression; |
||||
return false; |
||||
} |
||||
|
||||
// Assignment is only meaningful when assigning into an identifier.
|
||||
// The identifier must name a variable, not a constant. Variables
|
||||
// begin with '$'.
|
||||
string identifier; |
||||
if (PopValueOrIdentifier(NULL, &identifier) != POP_RESULT_IDENTIFIER) { |
||||
BPLOG(ERROR) << "PopValueOrIdentifier returned a value, but an " |
||||
"identifier is needed to assign " << |
||||
HexString(value) << ": " << expression; |
||||
return false; |
||||
} |
||||
if (identifier.empty() || identifier[0] != '$') { |
||||
BPLOG(ERROR) << "Can't assign " << HexString(value) << " to " << |
||||
identifier << ": " << expression; |
||||
return false; |
||||
} |
||||
|
||||
(*dictionary_)[identifier] = value; |
||||
if (assigned) |
||||
(*assigned)[identifier] = true; |
||||
} else { |
||||
// The token is not an operator, it's a literal value or an identifier.
|
||||
// Push it onto the stack as-is. Use push_back instead of PushValue
|
||||
// because PushValue pushes ValueType as a string, but token is already
|
||||
// a string.
|
||||
stack_.push_back(token); |
||||
} |
||||
} |
||||
|
||||
// If there's anything left on the stack, it indicates incomplete execution.
|
||||
// This is a failure case. If the stack is empty, evalution was complete
|
||||
// and successful.
|
||||
BPLOG_IF(ERROR, !stack_.empty()) << "Incomplete execution: " << expression; |
||||
return stack_.empty(); |
||||
} |
||||
|
||||
|
||||
template<typename ValueType> |
||||
typename PostfixEvaluator<ValueType>::PopResult |
||||
PostfixEvaluator<ValueType>::PopValueOrIdentifier( |
||||
ValueType *value, string *identifier) { |
||||
// There needs to be at least one element on the stack to pop.
|
||||
if (!stack_.size()) |
||||
return POP_RESULT_FAIL; |
||||
|
||||
string token = stack_.back(); |
||||
stack_.pop_back(); |
||||
|
||||
// First, try to treat the value as a literal. In order for this to
|
||||
// succed, the entire string must be parseable as ValueType. If this
|
||||
// isn't possible, it can't be a literal, so treat it as an identifier
|
||||
// instead.
|
||||
istringstream token_stream(token); |
||||
ValueType literal; |
||||
if (token_stream >> literal && token_stream.peek() == EOF) { |
||||
if (value) { |
||||
*value = literal; |
||||
} |
||||
return POP_RESULT_VALUE; |
||||
} else { |
||||
if (identifier) { |
||||
*identifier = token; |
||||
} |
||||
return POP_RESULT_IDENTIFIER; |
||||
} |
||||
} |
||||
|
||||
|
||||
template<typename ValueType> |
||||
bool PostfixEvaluator<ValueType>::PopValue(ValueType *value) { |
||||
ValueType literal; |
||||
string token; |
||||
PopResult result; |
||||
if ((result = PopValueOrIdentifier(&literal, &token)) == POP_RESULT_FAIL) { |
||||
return false; |
||||
} else if (result == POP_RESULT_VALUE) { |
||||
// This is the easy case.
|
||||
*value = literal; |
||||
} else { // result == POP_RESULT_IDENTIFIER
|
||||
// There was an identifier at the top of the stack. Resolve it to a
|
||||
// value by looking it up in the dictionary.
|
||||
typename DictionaryType::const_iterator iterator = |
||||
dictionary_->find(token); |
||||
if (iterator == dictionary_->end()) { |
||||
// The identifier wasn't found in the dictionary. Don't imply any
|
||||
// default value, just fail.
|
||||
BPLOG(ERROR) << "Identifier " << token << " not in dictionary"; |
||||
return false; |
||||
} |
||||
|
||||
*value = iterator->second; |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
|
||||
template<typename ValueType> |
||||
bool PostfixEvaluator<ValueType>::PopValues(ValueType *value1, |
||||
ValueType *value2) { |
||||
return PopValue(value2) && PopValue(value1); |
||||
} |
||||
|
||||
|
||||
template<typename ValueType> |
||||
void PostfixEvaluator<ValueType>::PushValue(const ValueType &value) { |
||||
ostringstream token_stream; |
||||
token_stream << value; |
||||
stack_.push_back(token_stream.str()); |
||||
} |
||||
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
|
||||
#endif // PROCESSOR_POSTFIX_EVALUATOR_INL_H__
|
@ -0,0 +1,158 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// postfix_evaluator.h: Postfix (reverse Polish) notation expression evaluator.
|
||||
//
|
||||
// PostfixEvaluator evaluates an expression, using the expression itself
|
||||
// in postfix (reverse Polish) notation and a dictionary mapping constants
|
||||
// and variables to their values. The evaluator supports standard
|
||||
// arithmetic operations, assignment into variables, and when an optional
|
||||
// MemoryRange is provided, dereferencing. (Any unary key-to-value operation
|
||||
// may be used with a MemoryRange implementation that returns the appropriate
|
||||
// values, but PostfixEvaluator was written with dereferencing in mind.)
|
||||
//
|
||||
// The expression language is simple. Expressions are supplied as strings,
|
||||
// with operands and operators delimited by whitespace. Operands may be
|
||||
// either literal values suitable for ValueType, or constants or variables,
|
||||
// which reference the dictionary. The supported binary operators are +
|
||||
// (addition), - (subtraction), * (multiplication), / (quotient of division),
|
||||
// and % (modulus of division). The unary ^ (dereference) operator is also
|
||||
// provided. These operators allow any operand to be either a literal
|
||||
// value, constant, or variable. Assignment (=) of any type of operand into
|
||||
// a variable is also supported.
|
||||
//
|
||||
// The dictionary is provided as a map with string keys. Keys beginning
|
||||
// with the '$' character are treated as variables. All other keys are
|
||||
// treated as constants. Any results must be assigned into variables in the
|
||||
// dictionary. These variables do not need to exist prior to calling
|
||||
// Evaluate, unless used in an expression prior to being assigned to. The
|
||||
// internal stack state is not made available after evaluation, and any
|
||||
// values remaining on the stack are treated as evidence of incomplete
|
||||
// execution and cause the evaluator to indicate failure.
|
||||
//
|
||||
// PostfixEvaluator is intended to support evaluation of "program strings"
|
||||
// obtained from MSVC frame data debugging information in pdb files as
|
||||
// returned by the DIA APIs.
|
||||
//
|
||||
// Author: Mark Mentovai
|
||||
|
||||
#ifndef PROCESSOR_POSTFIX_EVALUATOR_H__ |
||||
#define PROCESSOR_POSTFIX_EVALUATOR_H__ |
||||
|
||||
|
||||
#include <map> |
||||
#include <string> |
||||
#include <vector> |
||||
|
||||
namespace google_breakpad { |
||||
|
||||
using std::map; |
||||
using std::string; |
||||
using std::vector; |
||||
|
||||
class MemoryRegion; |
||||
|
||||
template<typename ValueType> |
||||
class PostfixEvaluator { |
||||
public: |
||||
typedef map<string, ValueType> DictionaryType; |
||||
typedef map<string, bool> DictionaryValidityType; |
||||
|
||||
// Create a PostfixEvaluator object that may be used (with Evaluate) on
|
||||
// one or more expressions. PostfixEvaluator does not take ownership of
|
||||
// either argument. |memory| may be NULL, in which case dereferencing
|
||||
// (^) will not be supported. |dictionary| may be NULL, but evaluation
|
||||
// will fail in that case unless set_dictionary is used before calling
|
||||
// Evaluate.
|
||||
PostfixEvaluator(DictionaryType *dictionary, MemoryRegion *memory) |
||||
: dictionary_(dictionary), memory_(memory), stack_() {} |
||||
|
||||
// Evaluate the expression. The results of execution will be stored
|
||||
// in one (or more) variables in the dictionary. Returns false if any
|
||||
// failures occure during execution, leaving variables in the dictionary
|
||||
// in an indeterminate state. If assigned is non-NULL, any keys set in
|
||||
// the dictionary as a result of evaluation will also be set to true in
|
||||
// assigned, providing a way to determine if an expression modifies any
|
||||
// of its input variables.
|
||||
bool Evaluate(const string &expression, DictionaryValidityType *assigned); |
||||
|
||||
DictionaryType* dictionary() const { return dictionary_; } |
||||
|
||||
// Reset the dictionary. PostfixEvaluator does not take ownership.
|
||||
void set_dictionary(DictionaryType *dictionary) {dictionary_ = dictionary; } |
||||
|
||||
private: |
||||
// Return values for PopValueOrIdentifier
|
||||
enum PopResult { |
||||
POP_RESULT_FAIL = 0, |
||||
POP_RESULT_VALUE, |
||||
POP_RESULT_IDENTIFIER |
||||
}; |
||||
|
||||
// Retrieves the topmost literal value, constant, or variable from the
|
||||
// stack. Returns POP_RESULT_VALUE if the topmost entry is a literal
|
||||
// value, and sets |value| accordingly. Returns POP_RESULT_IDENTIFIER
|
||||
// if the topmost entry is a constant or variable identifier, and sets
|
||||
// |identifier| accordingly. Returns POP_RESULT_FAIL on failure, such
|
||||
// as when the stack is empty.
|
||||
PopResult PopValueOrIdentifier(ValueType *value, string *identifier); |
||||
|
||||
// Retrieves the topmost value on the stack. If the topmost entry is
|
||||
// an identifier, the dictionary is queried for the identifier's value.
|
||||
// Returns false on failure, such as when the stack is empty or when
|
||||
// a nonexistent identifier is named.
|
||||
bool PopValue(ValueType *value); |
||||
|
||||
// Retrieves the top two values on the stack, in the style of PopValue.
|
||||
// value2 is popped before value1, so that value1 corresponds to the
|
||||
// entry that was pushed prior to value2. Returns false on failure.
|
||||
bool PopValues(ValueType *value1, ValueType *value2); |
||||
|
||||
// Pushes a new value onto the stack.
|
||||
void PushValue(const ValueType &value); |
||||
|
||||
// The dictionary mapping constant and variable identifiers (strings) to
|
||||
// values. Keys beginning with '$' are treated as variable names, and
|
||||
// PostfixEvaluator is free to create and modify these keys. Weak pointer.
|
||||
DictionaryType *dictionary_; |
||||
|
||||
// If non-NULL, the MemoryRegion used for dereference (^) operations.
|
||||
// If NULL, dereferencing is unsupported and will fail. Weak pointer.
|
||||
MemoryRegion *memory_; |
||||
|
||||
// The stack contains state information as execution progresses. Values
|
||||
// are pushed on to it as the expression string is read and as operations
|
||||
// yield values; values are popped when used as operands to operators.
|
||||
vector<string> stack_; |
||||
}; |
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
|
||||
#endif // PROCESSOR_POSTFIX_EVALUATOR_H__
|
@ -0,0 +1,210 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// range_map-inl.h: Range map implementation.
|
||||
//
|
||||
// See range_map.h for documentation.
|
||||
//
|
||||
// Author: Mark Mentovai
|
||||
|
||||
#ifndef PROCESSOR_RANGE_MAP_INL_H__ |
||||
#define PROCESSOR_RANGE_MAP_INL_H__ |
||||
|
||||
|
||||
#include <cassert> |
||||
|
||||
#include "processor/range_map.h" |
||||
#include "processor/logging.h" |
||||
|
||||
|
||||
namespace google_breakpad { |
||||
|
||||
|
||||
template<typename AddressType, typename EntryType> |
||||
bool RangeMap<AddressType, EntryType>::StoreRange(const AddressType &base, |
||||
const AddressType &size, |
||||
const EntryType &entry) { |
||||
AddressType high = base + size - 1; |
||||
|
||||
// Check for undersize or overflow.
|
||||
if (size <= 0 || high < base) { |
||||
// The processor will hit this case too frequently with common symbol
|
||||
// files in the size == 0 case, which is more suited to a DEBUG channel.
|
||||
// Filter those out since there's no DEBUG channel at the moment.
|
||||
BPLOG_IF(INFO, size != 0) << "StoreRange failed, " << HexString(base) << |
||||
"+" << HexString(size) << ", " << |
||||
HexString(high); |
||||
return false; |
||||
} |
||||
|
||||
// Ensure that this range does not overlap with another one already in the
|
||||
// map.
|
||||
MapConstIterator iterator_base = map_.lower_bound(base); |
||||
MapConstIterator iterator_high = map_.lower_bound(high); |
||||
|
||||
if (iterator_base != iterator_high) { |
||||
// Some other range begins in the space used by this range. It may be
|
||||
// contained within the space used by this range, or it may extend lower.
|
||||
// Regardless, it is an error.
|
||||
AddressType other_base = iterator_base->second.base(); |
||||
AddressType other_size = iterator_base->first - other_base + 1; |
||||
BPLOG(INFO) << "StoreRange failed, an existing range is contained by or " |
||||
"extends lower than the new range: new " << |
||||
HexString(base) << "+" << HexString(size) << ", existing " << |
||||
HexString(other_base) << "+" << HexString(other_size); |
||||
return false; |
||||
} |
||||
|
||||
if (iterator_high != map_.end()) { |
||||
if (iterator_high->second.base() <= high) { |
||||
// The range above this one overlaps with this one. It may fully
|
||||
// contain this range, or it may begin within this range and extend
|
||||
// higher. Regardless, it's an error.
|
||||
AddressType other_base = iterator_high->second.base(); |
||||
AddressType other_size = iterator_high->first - other_base + 1; |
||||
BPLOG(INFO) << "StoreRange failed, an existing range contains or " |
||||
"extends higher than the new range: new " << |
||||
HexString(base) << "+" << HexString(size) << |
||||
", existing " << |
||||
HexString(other_base) << "+" << HexString(other_size); |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
// Store the range in the map by its high address, so that lower_bound can
|
||||
// be used to quickly locate a range by address.
|
||||
map_.insert(MapValue(high, Range(base, entry))); |
||||
return true; |
||||
} |
||||
|
||||
|
||||
template<typename AddressType, typename EntryType> |
||||
bool RangeMap<AddressType, EntryType>::RetrieveRange( |
||||
const AddressType &address, EntryType *entry, |
||||
AddressType *entry_base, AddressType *entry_size) const { |
||||
BPLOG_IF(ERROR, !entry) << "RangeMap::RetrieveRange requires |entry|"; |
||||
assert(entry); |
||||
|
||||
MapConstIterator iterator = map_.lower_bound(address); |
||||
if (iterator == map_.end()) |
||||
return false; |
||||
|
||||
// The map is keyed by the high address of each range, so |address| is
|
||||
// guaranteed to be lower than the range's high address. If |range| is
|
||||
// not directly preceded by another range, it's possible for address to
|
||||
// be below the range's low address, though. When that happens, address
|
||||
// references something not within any range, so return false.
|
||||
if (address < iterator->second.base()) |
||||
return false; |
||||
|
||||
*entry = iterator->second.entry(); |
||||
if (entry_base) |
||||
*entry_base = iterator->second.base(); |
||||
if (entry_size) |
||||
*entry_size = iterator->first - iterator->second.base() + 1; |
||||
|
||||
return true; |
||||
} |
||||
|
||||
|
||||
template<typename AddressType, typename EntryType> |
||||
bool RangeMap<AddressType, EntryType>::RetrieveNearestRange( |
||||
const AddressType &address, EntryType *entry, |
||||
AddressType *entry_base, AddressType *entry_size) const { |
||||
BPLOG_IF(ERROR, !entry) << "RangeMap::RetrieveNearestRange requires |entry|"; |
||||
assert(entry); |
||||
|
||||
// If address is within a range, RetrieveRange can handle it.
|
||||
if (RetrieveRange(address, entry, entry_base, entry_size)) |
||||
return true; |
||||
|
||||
// upper_bound gives the first element whose key is greater than address,
|
||||
// but we want the first element whose key is less than or equal to address.
|
||||
// Decrement the iterator to get there, but not if the upper_bound already
|
||||
// points to the beginning of the map - in that case, address is lower than
|
||||
// the lowest stored key, so return false.
|
||||
MapConstIterator iterator = map_.upper_bound(address); |
||||
if (iterator == map_.begin()) |
||||
return false; |
||||
--iterator; |
||||
|
||||
*entry = iterator->second.entry(); |
||||
if (entry_base) |
||||
*entry_base = iterator->first; |
||||
if (entry_size) |
||||
*entry_size = iterator->first - iterator->second.base() + 1; |
||||
|
||||
return true; |
||||
} |
||||
|
||||
|
||||
template<typename AddressType, typename EntryType> |
||||
bool RangeMap<AddressType, EntryType>::RetrieveRangeAtIndex( |
||||
int index, EntryType *entry, |
||||
AddressType *entry_base, AddressType *entry_size) const { |
||||
BPLOG_IF(ERROR, !entry) << "RangeMap::RetrieveRangeAtIndex requires |entry|"; |
||||
assert(entry); |
||||
|
||||
if (index >= GetCount()) { |
||||
BPLOG(ERROR) << "Index out of range: " << index << "/" << GetCount(); |
||||
return false; |
||||
} |
||||
|
||||
// Walk through the map. Although it's ordered, it's not a vector, so it
|
||||
// can't be addressed directly by index.
|
||||
MapConstIterator iterator = map_.begin(); |
||||
for (int this_index = 0; this_index < index; ++this_index) |
||||
++iterator; |
||||
|
||||
*entry = iterator->second.entry(); |
||||
if (entry_base) |
||||
*entry_base = iterator->first; |
||||
if (entry_size) |
||||
*entry_size = iterator->first - iterator->second.base() + 1; |
||||
|
||||
return true; |
||||
} |
||||
|
||||
|
||||
template<typename AddressType, typename EntryType> |
||||
int RangeMap<AddressType, EntryType>::GetCount() const { |
||||
return map_.size(); |
||||
} |
||||
|
||||
|
||||
template<typename AddressType, typename EntryType> |
||||
void RangeMap<AddressType, EntryType>::Clear() { |
||||
map_.clear(); |
||||
} |
||||
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
|
||||
#endif // PROCESSOR_RANGE_MAP_INL_H__
|
@ -0,0 +1,126 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// range_map.h: Range maps.
|
||||
//
|
||||
// A range map associates a range of addresses with a specific object. This
|
||||
// is useful when certain objects of variable size are located within an
|
||||
// address space. The range map makes it simple to determine which object is
|
||||
// associated with a specific address, which may be any address within the
|
||||
// range associated with an object.
|
||||
//
|
||||
// Author: Mark Mentovai
|
||||
|
||||
#ifndef PROCESSOR_RANGE_MAP_H__ |
||||
#define PROCESSOR_RANGE_MAP_H__ |
||||
|
||||
|
||||
#include <map> |
||||
|
||||
|
||||
namespace google_breakpad { |
||||
|
||||
|
||||
template<typename AddressType, typename EntryType> |
||||
class RangeMap { |
||||
public: |
||||
RangeMap() : map_() {} |
||||
|
||||
// Inserts a range into the map. Returns false for a parameter error,
|
||||
// or if the location of the range would conflict with a range already
|
||||
// stored in the map.
|
||||
bool StoreRange(const AddressType &base, |
||||
const AddressType &size, |
||||
const EntryType &entry); |
||||
|
||||
// Locates the range encompassing the supplied address. If there is
|
||||
// no such range, returns false. entry_base and entry_size, if non-NULL,
|
||||
// are set to the base and size of the entry's range.
|
||||
bool RetrieveRange(const AddressType &address, EntryType *entry, |
||||
AddressType *entry_base, AddressType *entry_size) const; |
||||
|
||||
// Locates the range encompassing the supplied address, if one exists.
|
||||
// If no range encompasses the supplied address, locates the nearest range
|
||||
// to the supplied address that is lower than the address. Returns false
|
||||
// if no range meets these criteria. entry_base and entry_size, if
|
||||
// non-NULL, are set to the base and size of the entry's range.
|
||||
bool RetrieveNearestRange(const AddressType &address, EntryType *entry, |
||||
AddressType *entry_base, AddressType *entry_size) |
||||
const; |
||||
|
||||
// Treating all ranges as a list ordered by the address spaces that they
|
||||
// occupy, locates the range at the index specified by index. Returns
|
||||
// false if index is larger than the number of ranges stored. entry_base
|
||||
// and entry_size, if non-NULL, are set to the base and size of the entry's
|
||||
// range.
|
||||
//
|
||||
// RetrieveRangeAtIndex is not optimized for speedy operation.
|
||||
bool RetrieveRangeAtIndex(int index, EntryType *entry, |
||||
AddressType *entry_base, AddressType *entry_size) |
||||
const; |
||||
|
||||
// Returns the number of ranges stored in the RangeMap.
|
||||
int GetCount() const; |
||||
|
||||
// Empties the range map, restoring it to the state it was when it was
|
||||
// initially created.
|
||||
void Clear(); |
||||
|
||||
private: |
||||
class Range { |
||||
public: |
||||
Range(const AddressType &base, const EntryType &entry) |
||||
: base_(base), entry_(entry) {} |
||||
|
||||
AddressType base() const { return base_; } |
||||
EntryType entry() const { return entry_; } |
||||
|
||||
private: |
||||
// The base address of the range. The high address does not need to
|
||||
// be stored, because RangeMap uses it as the key to the map.
|
||||
const AddressType base_; |
||||
|
||||
// The entry corresponding to a range.
|
||||
const EntryType entry_; |
||||
}; |
||||
|
||||
// Convenience types.
|
||||
typedef std::map<AddressType, Range> AddressToRangeMap; |
||||
typedef typename AddressToRangeMap::const_iterator MapConstIterator; |
||||
typedef typename AddressToRangeMap::value_type MapValue; |
||||
|
||||
// Maps the high address of each range to a EntryType.
|
||||
AddressToRangeMap map_; |
||||
}; |
||||
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
|
||||
#endif // PROCESSOR_RANGE_MAP_H__
|
@ -0,0 +1,335 @@ |
||||
// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999.
|
||||
// Copyright (c) 2001, 2002 Peter Dimov
|
||||
//
|
||||
// Permission to copy, use, modify, sell and distribute this software
|
||||
// is granted provided this copyright notice appears in all copies.
|
||||
// This software is provided "as is" without express or implied
|
||||
// warranty, and with no claim as to its suitability for any purpose.
|
||||
//
|
||||
// See http://www.boost.org/libs/smart_ptr/scoped_ptr.htm for documentation.
|
||||
//
|
||||
|
||||
// scoped_ptr mimics a built-in pointer except that it guarantees deletion
|
||||
// of the object pointed to, either on destruction of the scoped_ptr or via
|
||||
// an explicit reset(). scoped_ptr is a simple solution for simple needs;
|
||||
// use shared_ptr or std::auto_ptr if your needs are more complex.
|
||||
|
||||
// *** NOTE ***
|
||||
// If your scoped_ptr is a class member of class FOO pointing to a
|
||||
// forward declared type BAR (as shown below), then you MUST use a non-inlined
|
||||
// version of the destructor. The destructor of a scoped_ptr (called from
|
||||
// FOO's destructor) must have a complete definition of BAR in order to
|
||||
// destroy it. Example:
|
||||
//
|
||||
// -- foo.h --
|
||||
// class BAR;
|
||||
//
|
||||
// class FOO {
|
||||
// public:
|
||||
// FOO();
|
||||
// ~FOO(); // Required for sources that instantiate class FOO to compile!
|
||||
//
|
||||
// private:
|
||||
// scoped_ptr<BAR> bar_;
|
||||
// };
|
||||
//
|
||||
// -- foo.cc --
|
||||
// #include "foo.h"
|
||||
// FOO::~FOO() {} // Empty, but must be non-inlined to FOO's class definition.
|
||||
|
||||
// scoped_ptr_malloc added by Google
|
||||
// When one of these goes out of scope, instead of doing a delete or
|
||||
// delete[], it calls free(). scoped_ptr_malloc<char> is likely to see
|
||||
// much more use than any other specializations.
|
||||
|
||||
// release() added by Google
|
||||
// Use this to conditionally transfer ownership of a heap-allocated object
|
||||
// to the caller, usually on method success.
|
||||
|
||||
#ifndef PROCESSOR_SCOPED_PTR_H__ |
||||
#define PROCESSOR_SCOPED_PTR_H__ |
||||
|
||||
#include <cstddef> // for std::ptrdiff_t |
||||
#include <assert.h> // for assert |
||||
#include <stdlib.h> // for free() decl |
||||
|
||||
namespace google_breakpad { |
||||
|
||||
template <typename T> |
||||
class scoped_ptr { |
||||
private: |
||||
|
||||
T* ptr; |
||||
|
||||
scoped_ptr(scoped_ptr const &); |
||||
scoped_ptr & operator=(scoped_ptr const &); |
||||
|
||||
public: |
||||
|
||||
typedef T element_type; |
||||
|
||||
explicit scoped_ptr(T* p = 0): ptr(p) {} |
||||
|
||||
~scoped_ptr() { |
||||
typedef char type_must_be_complete[sizeof(T)]; |
||||
delete ptr; |
||||
} |
||||
|
||||
void reset(T* p = 0) { |
||||
typedef char type_must_be_complete[sizeof(T)]; |
||||
|
||||
if (ptr != p) { |
||||
delete ptr; |
||||
ptr = p; |
||||
} |
||||
} |
||||
|
||||
T& operator*() const { |
||||
assert(ptr != 0); |
||||
return *ptr; |
||||
} |
||||
|
||||
T* operator->() const { |
||||
assert(ptr != 0); |
||||
return ptr; |
||||
} |
||||
|
||||
bool operator==(T* p) const { |
||||
return ptr == p; |
||||
} |
||||
|
||||
bool operator!=(T* p) const { |
||||
return ptr != p; |
||||
} |
||||
|
||||
T* get() const { |
||||
return ptr; |
||||
} |
||||
|
||||
void swap(scoped_ptr & b) { |
||||
T* tmp = b.ptr; |
||||
b.ptr = ptr; |
||||
ptr = tmp; |
||||
} |
||||
|
||||
T* release() { |
||||
T* tmp = ptr; |
||||
ptr = 0; |
||||
return tmp; |
||||
} |
||||
|
||||
private: |
||||
|
||||
// no reason to use these: each scoped_ptr should have its own object
|
||||
template <typename U> bool operator==(scoped_ptr<U> const& p) const; |
||||
template <typename U> bool operator!=(scoped_ptr<U> const& p) const; |
||||
}; |
||||
|
||||
template<typename T> inline |
||||
void swap(scoped_ptr<T>& a, scoped_ptr<T>& b) { |
||||
a.swap(b); |
||||
} |
||||
|
||||
template<typename T> inline |
||||
bool operator==(T* p, const scoped_ptr<T>& b) { |
||||
return p == b.get(); |
||||
} |
||||
|
||||
template<typename T> inline |
||||
bool operator!=(T* p, const scoped_ptr<T>& b) { |
||||
return p != b.get(); |
||||
} |
||||
|
||||
// scoped_array extends scoped_ptr to arrays. Deletion of the array pointed to
|
||||
// is guaranteed, either on destruction of the scoped_array or via an explicit
|
||||
// reset(). Use shared_array or std::vector if your needs are more complex.
|
||||
|
||||
template<typename T> |
||||
class scoped_array { |
||||
private: |
||||
|
||||
T* ptr; |
||||
|
||||
scoped_array(scoped_array const &); |
||||
scoped_array & operator=(scoped_array const &); |
||||
|
||||
public: |
||||
|
||||
typedef T element_type; |
||||
|
||||
explicit scoped_array(T* p = 0) : ptr(p) {} |
||||
|
||||
~scoped_array() { |
||||
typedef char type_must_be_complete[sizeof(T)]; |
||||
delete[] ptr; |
||||
} |
||||
|
||||
void reset(T* p = 0) { |
||||
typedef char type_must_be_complete[sizeof(T)]; |
||||
|
||||
if (ptr != p) { |
||||
delete [] ptr; |
||||
ptr = p; |
||||
} |
||||
} |
||||
|
||||
T& operator[](std::ptrdiff_t i) const { |
||||
assert(ptr != 0); |
||||
assert(i >= 0); |
||||
return ptr[i]; |
||||
} |
||||
|
||||
bool operator==(T* p) const { |
||||
return ptr == p; |
||||
} |
||||
|
||||
bool operator!=(T* p) const { |
||||
return ptr != p; |
||||
} |
||||
|
||||
T* get() const { |
||||
return ptr; |
||||
} |
||||
|
||||
void swap(scoped_array & b) { |
||||
T* tmp = b.ptr; |
||||
b.ptr = ptr; |
||||
ptr = tmp; |
||||
} |
||||
|
||||
T* release() { |
||||
T* tmp = ptr; |
||||
ptr = 0; |
||||
return tmp; |
||||
} |
||||
|
||||
private: |
||||
|
||||
// no reason to use these: each scoped_array should have its own object
|
||||
template <typename U> bool operator==(scoped_array<U> const& p) const; |
||||
template <typename U> bool operator!=(scoped_array<U> const& p) const; |
||||
}; |
||||
|
||||
template<class T> inline |
||||
void swap(scoped_array<T>& a, scoped_array<T>& b) { |
||||
a.swap(b); |
||||
} |
||||
|
||||
template<typename T> inline |
||||
bool operator==(T* p, const scoped_array<T>& b) { |
||||
return p == b.get(); |
||||
} |
||||
|
||||
template<typename T> inline |
||||
bool operator!=(T* p, const scoped_array<T>& b) { |
||||
return p != b.get(); |
||||
} |
||||
|
||||
|
||||
// This class wraps the c library function free() in a class that can be
|
||||
// passed as a template argument to scoped_ptr_malloc below.
|
||||
class ScopedPtrMallocFree { |
||||
public: |
||||
inline void operator()(void* x) const { |
||||
free(x); |
||||
} |
||||
}; |
||||
|
||||
// scoped_ptr_malloc<> is similar to scoped_ptr<>, but it accepts a
|
||||
// second template argument, the functor used to free the object.
|
||||
|
||||
template<typename T, typename FreeProc = ScopedPtrMallocFree> |
||||
class scoped_ptr_malloc { |
||||
private: |
||||
|
||||
T* ptr; |
||||
|
||||
scoped_ptr_malloc(scoped_ptr_malloc const &); |
||||
scoped_ptr_malloc & operator=(scoped_ptr_malloc const &); |
||||
|
||||
public: |
||||
|
||||
typedef T element_type; |
||||
|
||||
explicit scoped_ptr_malloc(T* p = 0): ptr(p) {} |
||||
|
||||
~scoped_ptr_malloc() { |
||||
typedef char type_must_be_complete[sizeof(T)]; |
||||
free_((void*) ptr); |
||||
} |
||||
|
||||
void reset(T* p = 0) { |
||||
typedef char type_must_be_complete[sizeof(T)]; |
||||
|
||||
if (ptr != p) { |
||||
free_((void*) ptr); |
||||
ptr = p; |
||||
} |
||||
} |
||||
|
||||
T& operator*() const { |
||||
assert(ptr != 0); |
||||
return *ptr; |
||||
} |
||||
|
||||
T* operator->() const { |
||||
assert(ptr != 0); |
||||
return ptr; |
||||
} |
||||
|
||||
bool operator==(T* p) const { |
||||
return ptr == p; |
||||
} |
||||
|
||||
bool operator!=(T* p) const { |
||||
return ptr != p; |
||||
} |
||||
|
||||
T* get() const { |
||||
return ptr; |
||||
} |
||||
|
||||
void swap(scoped_ptr_malloc & b) { |
||||
T* tmp = b.ptr; |
||||
b.ptr = ptr; |
||||
ptr = tmp; |
||||
} |
||||
|
||||
T* release() { |
||||
T* tmp = ptr; |
||||
ptr = 0; |
||||
return tmp; |
||||
} |
||||
|
||||
private: |
||||
|
||||
// no reason to use these: each scoped_ptr_malloc should have its own object
|
||||
template <typename U, typename GP> |
||||
bool operator==(scoped_ptr_malloc<U, GP> const& p) const; |
||||
template <typename U, typename GP> |
||||
bool operator!=(scoped_ptr_malloc<U, GP> const& p) const; |
||||
|
||||
static FreeProc const free_; |
||||
}; |
||||
|
||||
template<typename T, typename FP> |
||||
FP const scoped_ptr_malloc<T,FP>::free_ = FP(); |
||||
|
||||
template<typename T, typename FP> inline |
||||
void swap(scoped_ptr_malloc<T,FP>& a, scoped_ptr_malloc<T,FP>& b) { |
||||
a.swap(b); |
||||
} |
||||
|
||||
template<typename T, typename FP> inline |
||||
bool operator==(T* p, const scoped_ptr_malloc<T,FP>& b) { |
||||
return p == b.get(); |
||||
} |
||||
|
||||
template<typename T, typename FP> inline |
||||
bool operator!=(T* p, const scoped_ptr_malloc<T,FP>& b) { |
||||
return p != b.get(); |
||||
} |
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // PROCESSOR_SCOPED_PTR_H__
|
@ -0,0 +1,125 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// simple_symbol_supplier.h: A simple SymbolSupplier implementation
|
||||
//
|
||||
// SimpleSymbolSupplier is a straightforward implementation of SymbolSupplier
|
||||
// that stores symbol files in a filesystem tree. A SimpleSymbolSupplier is
|
||||
// created with one or more base directories, which are the root paths for all
|
||||
// symbol files. Each symbol file contained therein has a directory entry in
|
||||
// the base directory with a name identical to the corresponding debugging
|
||||
// file (pdb). Within each of these directories, there are subdirectories
|
||||
// named for the debugging file's identifier. For recent pdb files, this is
|
||||
// a concatenation of the pdb's uuid and age, presented in hexadecimal form,
|
||||
// without any dashes or separators. The uuid is in uppercase hexadecimal
|
||||
// and the age is in lowercase hexadecimal. Within that subdirectory,
|
||||
// SimpleSymbolSupplier expects to find the symbol file, which is named
|
||||
// identically to the debug file, but with a .sym extension. If the original
|
||||
// debug file had a name ending in .pdb, the .pdb extension will be replaced
|
||||
// with .sym. This sample hierarchy is rooted at the "symbols" base
|
||||
// directory:
|
||||
//
|
||||
// symbols
|
||||
// symbols/test_app.pdb
|
||||
// symbols/test_app.pdb/63FE4780728D49379B9D7BB6460CB42A1
|
||||
// symbols/test_app.pdb/63FE4780728D49379B9D7BB6460CB42A1/test_app.sym
|
||||
// symbols/kernel32.pdb
|
||||
// symbols/kernel32.pdb/BCE8785C57B44245A669896B6A19B9542
|
||||
// symbols/kernel32.pdb/BCE8785C57B44245A669896B6A19B9542/kernel32.sym
|
||||
//
|
||||
// In this case, the uuid of test_app.pdb is
|
||||
// 63fe4780-728d-4937-9b9d-7bb6460cb42a and its age is 1.
|
||||
//
|
||||
// This scheme was chosen to be roughly analogous to the way that
|
||||
// symbol files may be accessed from Microsoft Symbol Server. A hierarchy
|
||||
// used for Microsoft Symbol Server storage is usable as a hierarchy for
|
||||
// SimpleSymbolServer, provided that the pdb files are transformed to dumped
|
||||
// format using a tool such as dump_syms, and given a .sym extension.
|
||||
//
|
||||
// SimpleSymbolSupplier will iterate over all root paths searching for
|
||||
// a symbol file existing in that path.
|
||||
//
|
||||
// SimpleSymbolSupplier supports any debugging file which can be identified
|
||||
// by a CodeModule object's debug_file and debug_identifier accessors. The
|
||||
// expected ultimate source of these CodeModule objects are MinidumpModule
|
||||
// objects; it is this class that is responsible for assigning appropriate
|
||||
// values for debug_file and debug_identifier.
|
||||
//
|
||||
// Author: Mark Mentovai
|
||||
|
||||
#ifndef PROCESSOR_SIMPLE_SYMBOL_SUPPLIER_H__ |
||||
#define PROCESSOR_SIMPLE_SYMBOL_SUPPLIER_H__ |
||||
|
||||
#include <string> |
||||
#include <vector> |
||||
|
||||
#include "google_breakpad/processor/symbol_supplier.h" |
||||
|
||||
namespace google_breakpad { |
||||
|
||||
using std::string; |
||||
using std::vector; |
||||
|
||||
class CodeModule; |
||||
|
||||
class SimpleSymbolSupplier : public SymbolSupplier { |
||||
public: |
||||
// Creates a new SimpleSymbolSupplier, using path as the root path where
|
||||
// symbols are stored.
|
||||
explicit SimpleSymbolSupplier(const string &path) : paths_(1, path) {} |
||||
|
||||
// Creates a new SimpleSymbolSupplier, using paths as a list of root
|
||||
// paths where symbols may be stored.
|
||||
explicit SimpleSymbolSupplier(const vector<string> &paths) : paths_(paths) {} |
||||
|
||||
virtual ~SimpleSymbolSupplier() {} |
||||
|
||||
// Returns the path to the symbol file for the given module. See the
|
||||
// description above.
|
||||
virtual SymbolResult GetSymbolFile(const CodeModule *module, |
||||
const SystemInfo *system_info, |
||||
string *symbol_file); |
||||
|
||||
virtual SymbolResult GetSymbolFile(const CodeModule *module, |
||||
const SystemInfo *system_info, |
||||
string *symbol_file, |
||||
string *symbol_data); |
||||
protected: |
||||
SymbolResult GetSymbolFileAtPathFromRoot(const CodeModule *module, |
||||
const SystemInfo *system_info, |
||||
const string &root_path, |
||||
string *symbol_file); |
||||
|
||||
private: |
||||
vector<string> paths_; |
||||
}; |
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // PROCESSOR_SIMPLE_SYMBOL_SUPPLIER_H__
|
@ -0,0 +1,126 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// stack_frame_info.h: Holds debugging information about a stack frame.
|
||||
//
|
||||
// This structure is specific to Windows debugging information obtained
|
||||
// from pdb files using the DIA API.
|
||||
//
|
||||
// Author: Mark Mentovai
|
||||
|
||||
|
||||
#ifndef PROCESSOR_STACK_FRAME_INFO_H__ |
||||
#define PROCESSOR_STACK_FRAME_INFO_H__ |
||||
|
||||
#include <string> |
||||
|
||||
#include "google_breakpad/common/breakpad_types.h" |
||||
|
||||
namespace google_breakpad { |
||||
|
||||
struct StackFrameInfo { |
||||
public: |
||||
enum Validity { |
||||
VALID_NONE = 0, |
||||
VALID_PARAMETER_SIZE = 1, |
||||
VALID_ALL = -1 |
||||
}; |
||||
|
||||
StackFrameInfo() : valid(VALID_NONE), |
||||
prolog_size(0), |
||||
epilog_size(0), |
||||
parameter_size(0), |
||||
saved_register_size(0), |
||||
local_size(0), |
||||
max_stack_size(0), |
||||
allocates_base_pointer(0), |
||||
program_string() {} |
||||
|
||||
StackFrameInfo(u_int32_t set_prolog_size, |
||||
u_int32_t set_epilog_size, |
||||
u_int32_t set_parameter_size, |
||||
u_int32_t set_saved_register_size, |
||||
u_int32_t set_local_size, |
||||
u_int32_t set_max_stack_size, |
||||
int set_allocates_base_pointer, |
||||
const std::string set_program_string) |
||||
: valid(VALID_ALL), |
||||
prolog_size(set_prolog_size), |
||||
epilog_size(set_epilog_size), |
||||
parameter_size(set_parameter_size), |
||||
saved_register_size(set_saved_register_size), |
||||
local_size(set_local_size), |
||||
max_stack_size(set_max_stack_size), |
||||
allocates_base_pointer(set_allocates_base_pointer), |
||||
program_string(set_program_string) {} |
||||
|
||||
// CopyFrom makes "this" StackFrameInfo object identical to "that".
|
||||
void CopyFrom(const StackFrameInfo &that) { |
||||
valid = that.valid; |
||||
prolog_size = that.prolog_size; |
||||
epilog_size = that.epilog_size; |
||||
parameter_size = that.parameter_size; |
||||
saved_register_size = that.saved_register_size; |
||||
local_size = that.local_size; |
||||
max_stack_size = that.max_stack_size; |
||||
allocates_base_pointer = that.allocates_base_pointer; |
||||
program_string = that.program_string; |
||||
} |
||||
|
||||
// Clears the StackFrameInfo object so that users will see it as though
|
||||
// it contains no information.
|
||||
void Clear() { |
||||
valid = VALID_NONE; |
||||
program_string.erase(); |
||||
} |
||||
|
||||
// Identifies which fields in the structure are valid. This is of
|
||||
// type Validity, but it is defined as an int because it's not
|
||||
// possible to OR values into an enumerated type. Users must check
|
||||
// this field before using any other.
|
||||
int valid; |
||||
|
||||
// These values come from IDiaFrameData.
|
||||
u_int32_t prolog_size; |
||||
u_int32_t epilog_size; |
||||
u_int32_t parameter_size; |
||||
u_int32_t saved_register_size; |
||||
u_int32_t local_size; |
||||
u_int32_t max_stack_size; |
||||
|
||||
// Only one of allocates_base_pointer or program_string will be valid.
|
||||
// If program_string is empty, use allocates_base_pointer.
|
||||
bool allocates_base_pointer; |
||||
std::string program_string; |
||||
}; |
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
|
||||
#endif // PROCESSOR_STACK_FRAME_INFO_H__
|
@ -0,0 +1,80 @@ |
||||
// Copyright (c) 2007, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// stackwalker_amd64.h: amd64-specific stackwalker.
|
||||
//
|
||||
// Provides stack frames given amd64 register context and a memory region
|
||||
// corresponding to a amd64 stack.
|
||||
//
|
||||
// Author: Mark Mentovai, Ted Mielczarek
|
||||
|
||||
|
||||
#ifndef PROCESSOR_STACKWALKER_AMD64_H__ |
||||
#define PROCESSOR_STACKWALKER_AMD64_H__ |
||||
|
||||
|
||||
#include "google_breakpad/common/breakpad_types.h" |
||||
#include "google_breakpad/common/minidump_format.h" |
||||
#include "google_breakpad/processor/stackwalker.h" |
||||
|
||||
namespace google_breakpad { |
||||
|
||||
class CodeModules; |
||||
|
||||
class StackwalkerAMD64 : public Stackwalker { |
||||
public: |
||||
// context is a amd64 context object that gives access to amd64-specific
|
||||
// register state corresponding to the innermost called frame to be
|
||||
// included in the stack. The other arguments are passed directly through
|
||||
// to the base Stackwalker constructor.
|
||||
StackwalkerAMD64(const SystemInfo *system_info, |
||||
const MDRawContextAMD64 *context, |
||||
MemoryRegion *memory, |
||||
const CodeModules *modules, |
||||
SymbolSupplier *supplier, |
||||
SourceLineResolverInterface *resolver); |
||||
|
||||
private: |
||||
// Implementation of Stackwalker, using amd64 context (stack pointer in %rsp,
|
||||
// stack base in %rbp) and stack conventions (saved stack pointer at 0(%rbp))
|
||||
virtual StackFrame* GetContextFrame(); |
||||
virtual StackFrame* GetCallerFrame( |
||||
const CallStack *stack, |
||||
const vector< linked_ptr<StackFrameInfo> > &stack_frame_info); |
||||
|
||||
// Stores the CPU context corresponding to the innermost stack frame to
|
||||
// be returned by GetContextFrame.
|
||||
const MDRawContextAMD64 *context_; |
||||
}; |
||||
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
|
||||
#endif // PROCESSOR_STACKWALKER_AMD64_H__
|
@ -0,0 +1,81 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// stackwalker_ppc.h: ppc-specific stackwalker.
|
||||
//
|
||||
// Provides stack frames given ppc register context and a memory region
|
||||
// corresponding to a ppc stack.
|
||||
//
|
||||
// Author: Mark Mentovai
|
||||
|
||||
|
||||
#ifndef PROCESSOR_STACKWALKER_PPC_H__ |
||||
#define PROCESSOR_STACKWALKER_PPC_H__ |
||||
|
||||
|
||||
#include "google_breakpad/common/breakpad_types.h" |
||||
#include "google_breakpad/common/minidump_format.h" |
||||
#include "google_breakpad/processor/stackwalker.h" |
||||
|
||||
namespace google_breakpad { |
||||
|
||||
class CodeModules; |
||||
|
||||
class StackwalkerPPC : public Stackwalker { |
||||
public: |
||||
// context is a ppc context object that gives access to ppc-specific
|
||||
// register state corresponding to the innermost called frame to be
|
||||
// included in the stack. The other arguments are passed directly through
|
||||
// to the base Stackwalker constructor.
|
||||
StackwalkerPPC(const SystemInfo *system_info, |
||||
const MDRawContextPPC *context, |
||||
MemoryRegion *memory, |
||||
const CodeModules *modules, |
||||
SymbolSupplier *supplier, |
||||
SourceLineResolverInterface *resolver); |
||||
|
||||
private: |
||||
// Implementation of Stackwalker, using ppc context (stack pointer in %r1,
|
||||
// saved program counter in %srr0) and stack conventions (saved stack
|
||||
// pointer at 0(%r1), return address at 8(0(%r1)).
|
||||
virtual StackFrame* GetContextFrame(); |
||||
virtual StackFrame* GetCallerFrame( |
||||
const CallStack *stack, |
||||
const vector< linked_ptr<StackFrameInfo> > &stack_frame_info); |
||||
|
||||
// Stores the CPU context corresponding to the innermost stack frame to
|
||||
// be returned by GetContextFrame.
|
||||
const MDRawContextPPC *context_; |
||||
}; |
||||
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
|
||||
#endif // PROCESSOR_STACKWALKER_PPC_H__
|
@ -0,0 +1,86 @@ |
||||
// Copyright (c) 2007, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// stackwalker_sparc.h: sparc-specific stackwalker.
|
||||
//
|
||||
// Provides stack frames given sparc register context and a memory region
|
||||
// corresponding to an sparc stack.
|
||||
//
|
||||
// Author: Michael Shang
|
||||
|
||||
|
||||
#ifndef PROCESSOR_STACKWALKER_SPARC_H__ |
||||
#define PROCESSOR_STACKWALKER_SPARC_H__ |
||||
|
||||
|
||||
#include "google_breakpad/common/breakpad_types.h" |
||||
#include "google_breakpad/common/minidump_format.h" |
||||
#include "google_breakpad/processor/stackwalker.h" |
||||
|
||||
namespace google_breakpad { |
||||
|
||||
class CodeModules; |
||||
|
||||
class StackwalkerSPARC : public Stackwalker { |
||||
public: |
||||
// context is a sparc context object that gives access to sparc-specific
|
||||
// register state corresponding to the innermost called frame to be
|
||||
// included in the stack. The other arguments are passed directly through
|
||||
// to the base Stackwalker constructor.
|
||||
StackwalkerSPARC(const SystemInfo *system_info, |
||||
const MDRawContextSPARC *context, |
||||
MemoryRegion *memory, |
||||
const CodeModules *modules, |
||||
SymbolSupplier *supplier, |
||||
SourceLineResolverInterface *resolver); |
||||
|
||||
private: |
||||
// Implementation of Stackwalker, using x86 context (%ebp, %esp, %eip) and
|
||||
// stack conventions (saved %ebp at [%ebp], saved %eip at 4[%ebp], or
|
||||
// alternate conventions as guided by stack_frame_info_).
|
||||
// Implementation of Stackwalker, using ppc context (stack pointer in %r1,
|
||||
// saved program counter in %srr0) and stack conventions (saved stack
|
||||
// pointer at 0(%r1), return address at 8(0(%r1)).
|
||||
// Implementation of Stackwalker, using sparc context (%fp, %sp, %pc) and
|
||||
// stack conventions (saved %sp at)
|
||||
virtual StackFrame* GetContextFrame(); |
||||
virtual StackFrame* GetCallerFrame( |
||||
const CallStack *stack, |
||||
const vector< linked_ptr<StackFrameInfo> > &stack_frame_info); |
||||
|
||||
// Stores the CPU context corresponding to the innermost stack frame to
|
||||
// be returned by GetContextFrame.
|
||||
const MDRawContextSPARC *context_; |
||||
}; |
||||
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
|
||||
#endif // PROCESSOR_STACKWALKER_SPARC_H__
|
@ -0,0 +1,82 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// stackwalker_x86.h: x86-specific stackwalker.
|
||||
//
|
||||
// Provides stack frames given x86 register context and a memory region
|
||||
// corresponding to an x86 stack.
|
||||
//
|
||||
// Author: Mark Mentovai
|
||||
|
||||
|
||||
#ifndef PROCESSOR_STACKWALKER_X86_H__ |
||||
#define PROCESSOR_STACKWALKER_X86_H__ |
||||
|
||||
|
||||
#include "google_breakpad/common/breakpad_types.h" |
||||
#include "google_breakpad/common/minidump_format.h" |
||||
#include "google_breakpad/processor/stackwalker.h" |
||||
|
||||
namespace google_breakpad { |
||||
|
||||
class CodeModules; |
||||
|
||||
|
||||
class StackwalkerX86 : public Stackwalker { |
||||
public: |
||||
// context is an x86 context object that gives access to x86-specific
|
||||
// register state corresponding to the innermost called frame to be
|
||||
// included in the stack. The other arguments are passed directly through
|
||||
// to the base Stackwalker constructor.
|
||||
StackwalkerX86(const SystemInfo *system_info, |
||||
const MDRawContextX86 *context, |
||||
MemoryRegion *memory, |
||||
const CodeModules *modules, |
||||
SymbolSupplier *supplier, |
||||
SourceLineResolverInterface *resolver); |
||||
|
||||
private: |
||||
// Implementation of Stackwalker, using x86 context (%ebp, %esp, %eip) and
|
||||
// stack conventions (saved %ebp at [%ebp], saved %eip at 4[%ebp], or
|
||||
// alternate conventions as guided by stack_frame_info_).
|
||||
virtual StackFrame* GetContextFrame(); |
||||
virtual StackFrame* GetCallerFrame( |
||||
const CallStack *stack, |
||||
const vector< linked_ptr<StackFrameInfo> > &stack_frame_info); |
||||
|
||||
// Stores the CPU context corresponding to the innermost stack frame to
|
||||
// be returned by GetContextFrame.
|
||||
const MDRawContextX86 *context_; |
||||
}; |
||||
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
|
||||
#endif // PROCESSOR_STACKWALKER_X86_H__
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,9 @@ |
||||
To create the lib on Mac OS X: |
||||
|
||||
- qmake from r318 folder |
||||
- make install |
||||
|
||||
To create the lib on Windows: |
||||
|
||||
release.vc9.bat |
||||
|
@ -0,0 +1,17 @@ |
||||
set QT_BIN=C:\Qt\4.5.0\bin |
||||
|
||||
set VS_BIN="C:\Program Files\Microsoft Visual Studio 9.0\VC\bin" |
||||
set INNO_EXE="C:\Program Files\Inno Setup 5\iscc.exe " |
||||
set BUILD_DIR=".\build\win32\release" |
||||
|
||||
set PATH=%QT_BIN%;%PATH%; |
||||
|
||||
call %VS_BIN%\vcvars32.bat |
||||
|
||||
nmake clean |
||||
|
||||
rmdir /S /Q %BUILD_DIR% |
||||
|
||||
qmake |
||||
|
||||
nmake all |
@ -0,0 +1,55 @@ |
||||
CXX=g++
|
||||
CC=gcc
|
||||
|
||||
CXXFLAGS=-gstabs+ -I../../.. -Wall -D_REENTRANT
|
||||
LDFLAGS=-lpthread
|
||||
|
||||
OBJ_DIR=.
|
||||
BIN_DIR=.
|
||||
|
||||
THREAD_SRC=linux_thread.cc
|
||||
SHARE_SRC=../../minidump_file_writer.cc\
|
||||
../../../common/string_conversion.cc\
|
||||
../../../common/linux/file_id.cc\
|
||||
minidump_generator.cc
|
||||
HANDLER_SRC=exception_handler.cc\
|
||||
../../../common/linux/guid_creator.cc
|
||||
SHARE_C_SRC=../../../common/convert_UTF.c
|
||||
|
||||
THREAD_TEST_SRC=linux_thread_test.cc
|
||||
MINIDUMP_TEST_SRC=minidump_test.cc
|
||||
EXCEPTION_TEST_SRC=exception_handler_test.cc
|
||||
|
||||
THREAD_OBJ=$(patsubst %.cc,$(OBJ_DIR)/%.o,$(THREAD_SRC))
|
||||
SHARE_OBJ=$(patsubst %.cc,$(OBJ_DIR)/%.o,$(SHARE_SRC))
|
||||
HANDLER_OBJ=$(patsubst %.cc,$(OBJ_DIR)/%.o,$(HANDLER_SRC))
|
||||
SHARE_C_OBJ=$(patsubst %.c,$(OBJ_DIR)/%.o,$(SHARE_C_SRC)) md5.o
|
||||
THREAD_TEST_OBJ=$(patsubst %.cc,$(OBJ_DIR)/%.o, $(THREAD_TEST_SRC))\
|
||||
$(THREAD_OBJ)
|
||||
MINIDUMP_TEST_OBJ=$(patsubst %.cc,$(OBJ_DIR)/%.o, $(MINIDUMP_TEST_SRC))\
|
||||
$(THREAD_OBJ) $(SHARE_OBJ) $(SHARE_C_OBJ)
|
||||
EXCEPTION_TEST_OBJ=$(patsubst %.cc,$(OBJ_DIR)/%.o, $(EXCEPTION_TEST_SRC))\
|
||||
$(THREAD_OBJ) $(SHARE_OBJ) $(SHARE_C_OBJ) $(HANDLER_OBJ)
|
||||
|
||||
BIN=$(BIN_DIR)/minidump_test\
|
||||
$(BIN_DIR)/linux_thread_test\
|
||||
$(BIN_DIR)/exception_handler_test
|
||||
|
||||
.PHONY:all clean |
||||
|
||||
all:$(BIN) |
||||
|
||||
$(BIN_DIR)/linux_thread_test:$(THREAD_TEST_OBJ) |
||||
$(CXX) $(CXXFLAGS) $(LDFLAGS) $^ -o $@
|
||||
|
||||
$(BIN_DIR)/minidump_test:$(MINIDUMP_TEST_OBJ) |
||||
$(CXX) $(CXXFLAGS) $(LDFLAGS) $^ -o $@
|
||||
|
||||
$(BIN_DIR)/exception_handler_test:$(EXCEPTION_TEST_OBJ) |
||||
$(CXX) $(CXXFLAGS) $(LDFLAGS) $^ -o $@
|
||||
|
||||
md5.o:../../../common/md5.c |
||||
$(CC) $(CXXFLAGS) -c $^
|
||||
|
||||
clean: |
||||
rm -f $(BIN) *.o *.dmp
|
@ -0,0 +1,304 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Author: Li Liu
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <signal.h> |
||||
#include <sys/stat.h> |
||||
#include <sys/types.h> |
||||
#include <unistd.h> |
||||
|
||||
#include <cassert> |
||||
#include <cstdlib> |
||||
#include <ctime> |
||||
#include <linux/limits.h> |
||||
|
||||
#include "client/linux/handler/exception_handler.h" |
||||
#include "common/linux/guid_creator.h" |
||||
#include "google_breakpad/common/minidump_format.h" |
||||
|
||||
namespace google_breakpad { |
||||
|
||||
// Signals that we are interested.
|
||||
int SigTable[] = { |
||||
#if defined(SIGSEGV) |
||||
SIGSEGV, |
||||
#endif |
||||
#ifdef SIGABRT |
||||
SIGABRT, |
||||
#endif |
||||
#ifdef SIGFPE |
||||
SIGFPE, |
||||
#endif |
||||
#ifdef SIGILL |
||||
SIGILL, |
||||
#endif |
||||
#ifdef SIGBUS |
||||
SIGBUS, |
||||
#endif |
||||
}; |
||||
|
||||
std::vector<ExceptionHandler*> *ExceptionHandler::handler_stack_ = NULL; |
||||
int ExceptionHandler::handler_stack_index_ = 0; |
||||
pthread_mutex_t ExceptionHandler::handler_stack_mutex_ = |
||||
PTHREAD_MUTEX_INITIALIZER; |
||||
|
||||
ExceptionHandler::ExceptionHandler(const string &dump_path, |
||||
FilterCallback filter, |
||||
MinidumpCallback callback, |
||||
void *callback_context, |
||||
bool install_handler) |
||||
: filter_(filter), |
||||
callback_(callback), |
||||
callback_context_(callback_context), |
||||
dump_path_(), |
||||
installed_handler_(install_handler) { |
||||
set_dump_path(dump_path); |
||||
|
||||
act_.sa_handler = HandleException; |
||||
act_.sa_flags = SA_ONSTACK; |
||||
sigemptyset(&act_.sa_mask); |
||||
// now, make sure we're blocking all the signals we are handling
|
||||
// when we're handling any of them
|
||||
for ( size_t i = 0; i < sizeof(SigTable) / sizeof(SigTable[0]); ++i) { |
||||
sigaddset(&act_.sa_mask, SigTable[i]); |
||||
} |
||||
|
||||
if (install_handler) { |
||||
SetupHandler(); |
||||
pthread_mutex_lock(&handler_stack_mutex_); |
||||
if (handler_stack_ == NULL) |
||||
handler_stack_ = new std::vector<ExceptionHandler *>; |
||||
handler_stack_->push_back(this); |
||||
pthread_mutex_unlock(&handler_stack_mutex_); |
||||
} |
||||
} |
||||
|
||||
ExceptionHandler::~ExceptionHandler() { |
||||
TeardownAllHandler(); |
||||
pthread_mutex_lock(&handler_stack_mutex_); |
||||
if (handler_stack_->back() == this) { |
||||
handler_stack_->pop_back(); |
||||
} else { |
||||
fprintf(stderr, "warning: removing Breakpad handler out of order\n"); |
||||
for (std::vector<ExceptionHandler *>::iterator iterator = |
||||
handler_stack_->begin(); |
||||
iterator != handler_stack_->end(); |
||||
++iterator) { |
||||
if (*iterator == this) { |
||||
handler_stack_->erase(iterator); |
||||
} |
||||
} |
||||
} |
||||
|
||||
if (handler_stack_->empty()) { |
||||
// When destroying the last ExceptionHandler that installed a handler,
|
||||
// clean up the handler stack.
|
||||
delete handler_stack_; |
||||
handler_stack_ = NULL; |
||||
} |
||||
pthread_mutex_unlock(&handler_stack_mutex_); |
||||
} |
||||
|
||||
bool ExceptionHandler::WriteMinidump() { |
||||
bool success = InternalWriteMinidump(0, 0, NULL); |
||||
UpdateNextID(); |
||||
return success; |
||||
} |
||||
|
||||
// static
|
||||
bool ExceptionHandler::WriteMinidump(const string &dump_path, |
||||
MinidumpCallback callback, |
||||
void *callback_context) { |
||||
ExceptionHandler handler(dump_path, NULL, callback, |
||||
callback_context, false); |
||||
return handler.InternalWriteMinidump(0, 0, NULL); |
||||
} |
||||
|
||||
void ExceptionHandler::SetupHandler() { |
||||
// Signal on a different stack to avoid using the stack
|
||||
// of the crashing thread.
|
||||
struct sigaltstack sig_stack; |
||||
sig_stack.ss_sp = malloc(MINSIGSTKSZ); |
||||
if (sig_stack.ss_sp == NULL) |
||||
return; |
||||
sig_stack.ss_size = MINSIGSTKSZ; |
||||
sig_stack.ss_flags = 0; |
||||
|
||||
if (sigaltstack(&sig_stack, NULL) < 0) |
||||
return; |
||||
for (size_t i = 0; i < sizeof(SigTable) / sizeof(SigTable[0]); ++i) |
||||
SetupHandler(SigTable[i]); |
||||
} |
||||
|
||||
void ExceptionHandler::SetupHandler(int signo) { |
||||
|
||||
// We're storing pointers to the old signal action
|
||||
// structure, rather than copying the structure
|
||||
// because we can't count on the sa_mask field to
|
||||
// be scalar.
|
||||
struct sigaction *old_act = &old_actions_[signo]; |
||||
|
||||
if (sigaction(signo, &act_, old_act) < 0) |
||||
return; |
||||
} |
||||
|
||||
void ExceptionHandler::TeardownHandler(int signo) { |
||||
TeardownHandler(signo, NULL); |
||||
} |
||||
|
||||
void ExceptionHandler::TeardownHandler(int signo, struct sigaction *final_handler) { |
||||
if (old_actions_[signo].sa_handler) { |
||||
struct sigaction *act = &old_actions_[signo]; |
||||
sigaction(signo, act, final_handler); |
||||
memset(&old_actions_[signo], 0x0, sizeof(struct sigaction)); |
||||
} |
||||
} |
||||
|
||||
void ExceptionHandler::TeardownAllHandler() { |
||||
for (size_t i = 0; i < sizeof(SigTable) / sizeof(SigTable[0]); ++i) { |
||||
TeardownHandler(SigTable[i]); |
||||
} |
||||
} |
||||
|
||||
// static
|
||||
void ExceptionHandler::HandleException(int signo) { |
||||
// In Linux, the context information about the signal is put on the stack of
|
||||
// the signal handler frame as value parameter. For some reasons, the
|
||||
// prototype of the handler doesn't declare this information as parameter, we
|
||||
// will do it by hand. It is the second parameter above the signal number.
|
||||
// However, if we are being called by another signal handler passing the
|
||||
// signal up the chain, then we may not have this random extra parameter,
|
||||
// so we may have to walk the stack to find it. We do the actual work
|
||||
// on another thread, where it's a little safer, but we want the ebp
|
||||
// from this frame to find it.
|
||||
uintptr_t current_ebp = 0; |
||||
asm volatile ("movl %%ebp, %0" |
||||
:"=m"(current_ebp)); |
||||
|
||||
pthread_mutex_lock(&handler_stack_mutex_); |
||||
ExceptionHandler *current_handler = |
||||
handler_stack_->at(handler_stack_->size() - ++handler_stack_index_); |
||||
pthread_mutex_unlock(&handler_stack_mutex_); |
||||
|
||||
// Restore original handler.
|
||||
struct sigaction old_action; |
||||
current_handler->TeardownHandler(signo, &old_action); |
||||
|
||||
struct sigcontext *sig_ctx = NULL; |
||||
if (current_handler->InternalWriteMinidump(signo, current_ebp, &sig_ctx)) { |
||||
// Fully handled this exception, safe to exit.
|
||||
exit(EXIT_FAILURE); |
||||
} else { |
||||
// Exception not fully handled, will call the next handler in stack to
|
||||
// process it.
|
||||
if (old_action.sa_handler != NULL && sig_ctx != NULL) { |
||||
|
||||
// Have our own typedef, because of the comment above w.r.t signal
|
||||
// context on the stack
|
||||
typedef void (*SignalHandler)(int signo, struct sigcontext); |
||||
|
||||
SignalHandler old_handler = |
||||
reinterpret_cast<SignalHandler>(old_action.sa_handler); |
||||
|
||||
sigset_t old_set; |
||||
// Use SIG_BLOCK here because we don't want to unblock a signal
|
||||
// that the signal handler we're currently in needs to block
|
||||
sigprocmask(SIG_BLOCK, &old_action.sa_mask, &old_set); |
||||
old_handler(signo, *sig_ctx); |
||||
sigprocmask(SIG_SETMASK, &old_set, NULL); |
||||
} |
||||
|
||||
} |
||||
|
||||
pthread_mutex_lock(&handler_stack_mutex_); |
||||
current_handler->SetupHandler(signo); |
||||
--handler_stack_index_; |
||||
// All the handlers in stack have been invoked to handle the exception,
|
||||
// normally the process should be terminated and should not reach here.
|
||||
// In case we got here, ask the OS to handle it to avoid endless loop,
|
||||
// normally the OS will generate a core and termiate the process. This
|
||||
// may be desired to debug the program.
|
||||
if (handler_stack_index_ == 0) |
||||
signal(signo, SIG_DFL); |
||||
pthread_mutex_unlock(&handler_stack_mutex_); |
||||
} |
||||
|
||||
bool ExceptionHandler::InternalWriteMinidump(int signo, |
||||
uintptr_t sighandler_ebp, |
||||
struct sigcontext **sig_ctx) { |
||||
if (filter_ && !filter_(callback_context_)) |
||||
return false; |
||||
|
||||
bool success = false; |
||||
// Block all the signals we want to process when writting minidump.
|
||||
// We don't want it to be interrupted.
|
||||
sigset_t sig_blocked, sig_old; |
||||
bool blocked = true; |
||||
sigfillset(&sig_blocked); |
||||
for (size_t i = 0; i < sizeof(SigTable) / sizeof(SigTable[0]); ++i) |
||||
sigdelset(&sig_blocked, SigTable[i]); |
||||
if (sigprocmask(SIG_BLOCK, &sig_blocked, &sig_old) != 0) { |
||||
blocked = false; |
||||
fprintf(stderr, "google_breakpad::ExceptionHandler::HandleException: " |
||||
"failed to block signals.\n"); |
||||
} |
||||
|
||||
success = minidump_generator_.WriteMinidumpToFile( |
||||
next_minidump_path_c_, signo, sighandler_ebp, sig_ctx); |
||||
|
||||
// Unblock the signals.
|
||||
if (blocked) { |
||||
sigprocmask(SIG_SETMASK, &sig_old, NULL); |
||||
} |
||||
|
||||
if (callback_) |
||||
success = callback_(dump_path_c_, next_minidump_id_c_, |
||||
callback_context_, success); |
||||
return success; |
||||
} |
||||
|
||||
void ExceptionHandler::UpdateNextID() { |
||||
GUID guid; |
||||
char guid_str[kGUIDStringLength + 1]; |
||||
if (CreateGUID(&guid) && GUIDToString(&guid, guid_str, sizeof(guid_str))) { |
||||
next_minidump_id_ = guid_str; |
||||
next_minidump_id_c_ = next_minidump_id_.c_str(); |
||||
|
||||
char minidump_path[PATH_MAX]; |
||||
snprintf(minidump_path, sizeof(minidump_path), "%s/%s.dmp", |
||||
dump_path_c_, |
||||
guid_str); |
||||
|
||||
next_minidump_path_ = minidump_path; |
||||
next_minidump_path_c_ = next_minidump_path_.c_str(); |
||||
} |
||||
} |
||||
|
||||
} // namespace google_breakpad
|
@ -0,0 +1,226 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Author: Li Liu
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef CLIENT_LINUX_HANDLER_EXCEPTION_HANDLER_H__ |
||||
#define CLIENT_LINUX_HANDLER_EXCEPTION_HANDLER_H__ |
||||
|
||||
#include <pthread.h> |
||||
|
||||
#include <map> |
||||
#include <string> |
||||
#include <signal.h> |
||||
#include <vector> |
||||
|
||||
#include "client/linux/handler/minidump_generator.h" |
||||
|
||||
// Context information when exception occured.
|
||||
struct sigcontex; |
||||
|
||||
namespace google_breakpad { |
||||
|
||||
using std::string; |
||||
|
||||
//
|
||||
// ExceptionHandler
|
||||
//
|
||||
// ExceptionHandler can write a minidump file when an exception occurs,
|
||||
// or when WriteMinidump() is called explicitly by your program.
|
||||
//
|
||||
// To have the exception handler write minidumps when an uncaught exception
|
||||
// (crash) occurs, you should create an instance early in the execution
|
||||
// of your program, and keep it around for the entire time you want to
|
||||
// have crash handling active (typically, until shutdown).
|
||||
// (NOTE): There should be only be one this kind of exception handler
|
||||
// object per process.
|
||||
//
|
||||
// If you want to write minidumps without installing the exception handler,
|
||||
// you can create an ExceptionHandler with install_handler set to false,
|
||||
// then call WriteMinidump. You can also use this technique if you want to
|
||||
// use different minidump callbacks for different call sites.
|
||||
//
|
||||
// In either case, a callback function is called when a minidump is written,
|
||||
// which receives the unqiue id of the minidump. The caller can use this
|
||||
// id to collect and write additional application state, and to launch an
|
||||
// external crash-reporting application.
|
||||
//
|
||||
// Caller should try to make the callbacks as crash-friendly as possible,
|
||||
// it should avoid use heap memory allocation as much as possible.
|
||||
//
|
||||
class ExceptionHandler { |
||||
public: |
||||
// A callback function to run before Breakpad performs any substantial
|
||||
// processing of an exception. A FilterCallback is called before writing
|
||||
// a minidump. context is the parameter supplied by the user as
|
||||
// callback_context when the handler was created.
|
||||
//
|
||||
// If a FilterCallback returns true, Breakpad will continue processing,
|
||||
// attempting to write a minidump. If a FilterCallback returns false,
|
||||
// Breakpad will immediately report the exception as unhandled without
|
||||
// writing a minidump, allowing another handler the opportunity to handle it.
|
||||
typedef bool (*FilterCallback)(void *context); |
||||
|
||||
// A callback function to run after the minidump has been written.
|
||||
// minidump_id is a unique id for the dump, so the minidump
|
||||
// file is <dump_path>\<minidump_id>.dmp. context is the parameter supplied
|
||||
// by the user as callback_context when the handler was created. succeeded
|
||||
// indicates whether a minidump file was successfully written.
|
||||
//
|
||||
// If an exception occurred and the callback returns true, Breakpad will
|
||||
// treat the exception as fully-handled, suppressing any other handlers from
|
||||
// being notified of the exception. If the callback returns false, Breakpad
|
||||
// will treat the exception as unhandled, and allow another handler to handle
|
||||
// it. If there are no other handlers, Breakpad will report the exception to
|
||||
// the system as unhandled, allowing a debugger or native crash dialog the
|
||||
// opportunity to handle the exception. Most callback implementations
|
||||
// should normally return the value of |succeeded|, or when they wish to
|
||||
// not report an exception of handled, false. Callbacks will rarely want to
|
||||
// return true directly (unless |succeeded| is true).
|
||||
typedef bool (*MinidumpCallback)(const char *dump_path, |
||||
const char *minidump_id, |
||||
void *context, |
||||
bool succeeded); |
||||
|
||||
// Creates a new ExceptionHandler instance to handle writing minidumps.
|
||||
// Before writing a minidump, the optional filter callback will be called.
|
||||
// Its return value determines whether or not Breakpad should write a
|
||||
// minidump. Minidump files will be written to dump_path, and the optional
|
||||
// callback is called after writing the dump file, as described above.
|
||||
// If install_handler is true, then a minidump will be written whenever
|
||||
// an unhandled exception occurs. If it is false, minidumps will only
|
||||
// be written when WriteMinidump is called.
|
||||
ExceptionHandler(const string &dump_path, |
||||
FilterCallback filter, MinidumpCallback callback, |
||||
void *callback_context, |
||||
bool install_handler); |
||||
~ExceptionHandler(); |
||||
|
||||
// Get and set the minidump path.
|
||||
string dump_path() const { return dump_path_; } |
||||
void set_dump_path(const string &dump_path) { |
||||
dump_path_ = dump_path; |
||||
dump_path_c_ = dump_path_.c_str(); |
||||
UpdateNextID(); |
||||
} |
||||
|
||||
// Writes a minidump immediately. This can be used to capture the
|
||||
// execution state independently of a crash. Returns true on success.
|
||||
bool WriteMinidump(); |
||||
|
||||
// Convenience form of WriteMinidump which does not require an
|
||||
// ExceptionHandler instance.
|
||||
static bool WriteMinidump(const string &dump_path, |
||||
MinidumpCallback callback, |
||||
void *callback_context); |
||||
|
||||
private: |
||||
// Setup crash handler.
|
||||
void SetupHandler(); |
||||
// Setup signal handler for a signal.
|
||||
void SetupHandler(int signo); |
||||
// Teardown the handler for a signal.
|
||||
void TeardownHandler(int signo); |
||||
// Teardown the handler for a signal.
|
||||
void TeardownHandler(int signo, struct sigaction *old); |
||||
// Teardown all handlers.
|
||||
void TeardownAllHandler(); |
||||
|
||||
// Signal handler.
|
||||
static void HandleException(int signo); |
||||
|
||||
// If called from a signal handler, sighandler_ebp is the ebp of
|
||||
// that signal handler's frame, and sig_ctx is an out parameter
|
||||
// that will be set to point at the sigcontext that was placed
|
||||
// on the stack by the kernel. You can pass zero and NULL
|
||||
// for the second and third parameters if you are not calling
|
||||
// this from a signal handler.
|
||||
bool InternalWriteMinidump(int signo, uintptr_t sighandler_ebp, |
||||
struct sigcontext **sig_ctx); |
||||
|
||||
// Generates a new ID and stores it in next_minidump_id, and stores the
|
||||
// path of the next minidump to be written in next_minidump_path_.
|
||||
void UpdateNextID(); |
||||
|
||||
private: |
||||
FilterCallback filter_; |
||||
MinidumpCallback callback_; |
||||
void *callback_context_; |
||||
|
||||
// The directory in which a minidump will be written, set by the dump_path
|
||||
// argument to the constructor, or set_dump_path.
|
||||
string dump_path_; |
||||
|
||||
// The basename of the next minidump to be written, without the extension
|
||||
string next_minidump_id_; |
||||
|
||||
// The full pathname of the next minidump to be written, including the file
|
||||
// extension
|
||||
string next_minidump_path_; |
||||
|
||||
// Pointers to C-string representations of the above. These are set
|
||||
// when the above are set so we can avoid calling c_str during
|
||||
// an exception.
|
||||
const char *dump_path_c_; |
||||
const char *next_minidump_id_c_; |
||||
const char *next_minidump_path_c_; |
||||
|
||||
// True if the ExceptionHandler installed an unhandled exception filter
|
||||
// when created (with an install_handler parameter set to true).
|
||||
bool installed_handler_; |
||||
|
||||
// The global exception handler stack. This is need becuase there may exist
|
||||
// multiple ExceptionHandler instances in a process. Each will have itself
|
||||
// registered in this stack.
|
||||
static std::vector<ExceptionHandler *> *handler_stack_; |
||||
// The index of the handler that should handle the next exception.
|
||||
static int handler_stack_index_; |
||||
static pthread_mutex_t handler_stack_mutex_; |
||||
|
||||
// The minidump generator.
|
||||
MinidumpGenerator minidump_generator_; |
||||
|
||||
// disallow copy ctor and operator=
|
||||
explicit ExceptionHandler(const ExceptionHandler &); |
||||
void operator=(const ExceptionHandler &); |
||||
|
||||
// The sigactions structure we use for each signal
|
||||
struct sigaction act_; |
||||
|
||||
|
||||
// Keep the previous handlers for the signal.
|
||||
// We're wasting a bit of memory here since we only change
|
||||
// the handler for some signals but i want to avoid allocating
|
||||
// memory in the signal handler
|
||||
struct sigaction old_actions_[NSIG]; |
||||
}; |
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // CLIENT_LINUX_HANDLER_EXCEPTION_HANDLER_H__
|
@ -0,0 +1,124 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Author: Li Liu
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <pthread.h> |
||||
#include <unistd.h> |
||||
|
||||
#include <cassert> |
||||
#include <cstdio> |
||||
#include <cstdlib> |
||||
#include <cstring> |
||||
|
||||
#include "client/linux/handler/exception_handler.h" |
||||
#include "client/linux/handler/linux_thread.h" |
||||
|
||||
using namespace google_breakpad; |
||||
|
||||
// Thread use this to see if it should stop working.
|
||||
static bool should_exit = false; |
||||
|
||||
static int foo2(int arg) { |
||||
// Stack variable, used for debugging stack dumps.
|
||||
/*DDDebug*/printf("%s:%d\n", __FUNCTION__, __LINE__); |
||||
int c = 0xcccccccc; |
||||
fprintf(stderr, "Thread trying to crash: %x\n", getpid()); |
||||
c = *reinterpret_cast<int *>(0x5); |
||||
return c; |
||||
} |
||||
|
||||
static int foo(int arg) { |
||||
// Stack variable, used for debugging stack dumps.
|
||||
int b = 0xbbbbbbbb; |
||||
b = foo2(b); |
||||
return b; |
||||
} |
||||
|
||||
static void *thread_crash(void *) { |
||||
// Stack variable, used for debugging stack dumps.
|
||||
int a = 0xaaaaaaaa; |
||||
sleep(1); |
||||
a = foo(a); |
||||
printf("%x\n", a); |
||||
return NULL; |
||||
} |
||||
|
||||
static void *thread_main(void *) { |
||||
while (!should_exit) |
||||
sleep(1); |
||||
return NULL; |
||||
} |
||||
|
||||
static void CreateCrashThread() { |
||||
pthread_t h; |
||||
pthread_create(&h, NULL, thread_crash, NULL); |
||||
pthread_detach(h); |
||||
} |
||||
|
||||
// Create working threads.
|
||||
static void CreateThread(int num) { |
||||
pthread_t h; |
||||
for (int i = 0; i < num; ++i) { |
||||
pthread_create(&h, NULL, thread_main, NULL); |
||||
pthread_detach(h); |
||||
} |
||||
} |
||||
|
||||
// Callback when minidump written.
|
||||
static bool MinidumpCallback(const char *dump_path, |
||||
const char *minidump_id, |
||||
void *context, |
||||
bool succeeded) { |
||||
int index = reinterpret_cast<int>(context); |
||||
printf("%d %s: %s is dumped\n", index, __FUNCTION__, minidump_id); |
||||
if (index == 0) { |
||||
should_exit = true; |
||||
return true; |
||||
} |
||||
// Don't process it.
|
||||
return false; |
||||
} |
||||
|
||||
int main(int argc, char *argv[]) { |
||||
int handler_index = 0; |
||||
ExceptionHandler handler_ignore(".", NULL, MinidumpCallback, |
||||
(void*)handler_index, true); |
||||
++handler_index; |
||||
ExceptionHandler handler_process(".", NULL, MinidumpCallback, |
||||
(void*)handler_index, true); |
||||
CreateCrashThread(); |
||||
CreateThread(10); |
||||
|
||||
while (true) |
||||
sleep(1); |
||||
should_exit = true; |
||||
|
||||
return 0; |
||||
} |
@ -0,0 +1,411 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Author: Li Liu
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
#include <errno.h> |
||||
#include <dirent.h> |
||||
#include <fcntl.h> |
||||
#include <sys/ptrace.h> |
||||
#include <sys/stat.h> |
||||
#include <sys/types.h> |
||||
#include <unistd.h> |
||||
#include <sys/wait.h> |
||||
#include <string.h> |
||||
|
||||
#include <algorithm> |
||||
#include <cassert> |
||||
#include <cstdio> |
||||
#include <cstdlib> |
||||
#include <functional> |
||||
|
||||
#include "client/linux/handler/linux_thread.h" |
||||
|
||||
using namespace google_breakpad; |
||||
|
||||
// This unamed namespace contains helper function.
|
||||
namespace { |
||||
|
||||
// Context information for the callbacks when validating address by listing
|
||||
// modules.
|
||||
struct AddressValidatingContext { |
||||
uintptr_t address; |
||||
bool is_mapped; |
||||
|
||||
AddressValidatingContext() : address(0UL), is_mapped(false) { |
||||
} |
||||
}; |
||||
|
||||
// Convert from string to int.
|
||||
bool LocalAtoi(char *s, int *r) { |
||||
assert(s != NULL); |
||||
assert(r != NULL); |
||||
char *endptr = NULL; |
||||
int ret = strtol(s, &endptr, 10); |
||||
if (endptr == s) |
||||
return false; |
||||
*r = ret; |
||||
return true; |
||||
} |
||||
|
||||
// Fill the proc path of a thread given its id.
|
||||
void FillProcPath(int pid, char *path, int path_size) { |
||||
char pid_str[32]; |
||||
snprintf(pid_str, sizeof(pid_str), "%d", pid); |
||||
snprintf(path, path_size, "/proc/%s/", pid_str); |
||||
} |
||||
|
||||
// Read thread info from /proc/$pid/status.
|
||||
bool ReadThreadInfo(int pid, ThreadInfo *info) { |
||||
assert(info != NULL); |
||||
char status_path[80]; |
||||
// Max size we want to read from status file.
|
||||
static const int kStatusMaxSize = 1024; |
||||
char status_content[kStatusMaxSize]; |
||||
|
||||
FillProcPath(pid, status_path, sizeof(status_path)); |
||||
strcat(status_path, "status"); |
||||
int fd = open(status_path, O_RDONLY, 0); |
||||
if (fd < 0) |
||||
return false; |
||||
|
||||
int num_read = read(fd, status_content, kStatusMaxSize - 1); |
||||
if (num_read < 0) { |
||||
close(fd); |
||||
return false; |
||||
} |
||||
close(fd); |
||||
status_content[num_read] = '\0'; |
||||
|
||||
char *tgid_start = strstr(status_content, "Tgid:"); |
||||
if (tgid_start) |
||||
sscanf(tgid_start, "Tgid:\t%d\n", &(info->tgid)); |
||||
else |
||||
// tgid not supported by kernel??
|
||||
info->tgid = 0; |
||||
|
||||
tgid_start = strstr(status_content, "Pid:"); |
||||
if (tgid_start) { |
||||
sscanf(tgid_start, "Pid:\t%d\n" "PPid:\t%d\n", &(info->pid), |
||||
&(info->ppid)); |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
// Callback invoked for each mapped module.
|
||||
// It use the module's adderss range to validate the address.
|
||||
bool IsAddressInModuleCallback(const ModuleInfo &module_info, |
||||
void *context) { |
||||
AddressValidatingContext *addr = |
||||
reinterpret_cast<AddressValidatingContext *>(context); |
||||
addr->is_mapped = ((addr->address >= module_info.start_addr) && |
||||
(addr->address <= module_info.start_addr + |
||||
module_info.size)); |
||||
return !addr->is_mapped; |
||||
} |
||||
|
||||
#if defined(__i386__) && !defined(NO_FRAME_POINTER) |
||||
void *GetNextFrame(void **last_ebp) { |
||||
void *sp = *last_ebp; |
||||
if ((unsigned long)sp == (unsigned long)last_ebp) |
||||
return NULL; |
||||
if ((unsigned long)sp & (sizeof(void *) - 1)) |
||||
return NULL; |
||||
if ((unsigned long)sp - (unsigned long)last_ebp > 100000) |
||||
return NULL; |
||||
return sp; |
||||
} |
||||
#else |
||||
void *GetNextFrame(void **last_ebp) { |
||||
return reinterpret_cast<void*>(last_ebp); |
||||
} |
||||
#endif |
||||
|
||||
// Suspend a thread by attaching to it.
|
||||
bool SuspendThread(int pid, void *context) { |
||||
// This may fail if the thread has just died or debugged.
|
||||
errno = 0; |
||||
if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) != 0 && |
||||
errno != 0) { |
||||
return false; |
||||
} |
||||
while (waitpid(pid, NULL, __WALL) < 0) { |
||||
if (errno != EINTR) { |
||||
ptrace(PTRACE_DETACH, pid, NULL, NULL); |
||||
return false; |
||||
} |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
// Resume a thread by detaching from it.
|
||||
bool ResumeThread(int pid, void *context) { |
||||
return ptrace(PTRACE_DETACH, pid, NULL, NULL) >= 0; |
||||
} |
||||
|
||||
// Callback to get the thread information.
|
||||
// Will be called for each thread found.
|
||||
bool ThreadInfoCallback(int pid, void *context) { |
||||
CallbackParam<ThreadCallback> *thread_callback = |
||||
reinterpret_cast<CallbackParam<ThreadCallback> *>(context); |
||||
ThreadInfo thread_info; |
||||
if (ReadThreadInfo(pid, &thread_info) && thread_callback) { |
||||
// Invoke callback from caller.
|
||||
return (thread_callback->call_back)(thread_info, thread_callback->context); |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
} // namespace
|
||||
|
||||
namespace google_breakpad { |
||||
|
||||
LinuxThread::LinuxThread(int pid) : pid_(pid) , threads_suspened_(false) { |
||||
} |
||||
|
||||
LinuxThread::~LinuxThread() { |
||||
if (threads_suspened_) |
||||
ResumeAllThreads(); |
||||
} |
||||
|
||||
int LinuxThread::SuspendAllThreads() { |
||||
CallbackParam<PidCallback> callback_param(SuspendThread, NULL); |
||||
int thread_count = 0; |
||||
if ((thread_count = IterateProcSelfTask(pid_, &callback_param)) > 0) |
||||
threads_suspened_ = true; |
||||
return thread_count; |
||||
} |
||||
|
||||
void LinuxThread::ResumeAllThreads() const { |
||||
CallbackParam<PidCallback> callback_param(ResumeThread, NULL); |
||||
IterateProcSelfTask(pid_, &callback_param); |
||||
} |
||||
|
||||
int LinuxThread::GetThreadCount() const { |
||||
return IterateProcSelfTask(pid_, NULL); |
||||
} |
||||
|
||||
int LinuxThread::ListThreads( |
||||
CallbackParam<ThreadCallback> *thread_callback_param) const { |
||||
CallbackParam<PidCallback> callback_param(ThreadInfoCallback, |
||||
thread_callback_param); |
||||
return IterateProcSelfTask(pid_, &callback_param); |
||||
} |
||||
|
||||
bool LinuxThread::GetRegisters(int pid, user_regs_struct *regs) const { |
||||
assert(regs); |
||||
return (regs != NULL && |
||||
(ptrace(PTRACE_GETREGS, pid, NULL, regs) == 0) && |
||||
errno == 0); |
||||
} |
||||
|
||||
// Get the floating-point registers of a thread.
|
||||
// The caller must get the thread pid by ListThreads.
|
||||
bool LinuxThread::GetFPRegisters(int pid, user_fpregs_struct *regs) const { |
||||
assert(regs); |
||||
return (regs != NULL && |
||||
(ptrace(PTRACE_GETREGS, pid, NULL, regs) ==0) && |
||||
errno == 0); |
||||
} |
||||
|
||||
bool LinuxThread::GetFPXRegisters(int pid, user_fpxregs_struct *regs) const { |
||||
assert(regs); |
||||
return (regs != NULL && |
||||
(ptrace(PTRACE_GETFPREGS, pid, NULL, regs) != 0) && |
||||
errno == 0); |
||||
} |
||||
|
||||
bool LinuxThread::GetDebugRegisters(int pid, DebugRegs *regs) const { |
||||
assert(regs); |
||||
|
||||
#define GET_DR(name, num)\ |
||||
name->dr##num = ptrace(PTRACE_PEEKUSER, pid,\
|
||||
offsetof(struct user, u_debugreg[num]), NULL) |
||||
GET_DR(regs, 0); |
||||
GET_DR(regs, 1); |
||||
GET_DR(regs, 2); |
||||
GET_DR(regs, 3); |
||||
GET_DR(regs, 4); |
||||
GET_DR(regs, 5); |
||||
GET_DR(regs, 6); |
||||
GET_DR(regs, 7); |
||||
return true; |
||||
} |
||||
|
||||
int LinuxThread::GetThreadStackDump(uintptr_t current_ebp, |
||||
uintptr_t current_esp, |
||||
void *buf, |
||||
int buf_size) const { |
||||
assert(buf); |
||||
assert(buf_size > 0); |
||||
|
||||
uintptr_t stack_bottom = GetThreadStackBottom(current_ebp); |
||||
int size = stack_bottom - current_esp; |
||||
size = buf_size > size ? size : buf_size; |
||||
if (size > 0) |
||||
memcpy(buf, reinterpret_cast<void*>(current_esp), size); |
||||
return size; |
||||
} |
||||
|
||||
// Get the stack bottom of a thread by stack walking. It works
|
||||
// unless the stack has been corrupted or the frame pointer has been omited.
|
||||
// This is just a temporary solution before we get better ideas about how
|
||||
// this can be done.
|
||||
//
|
||||
// We will check each frame address by checking into module maps.
|
||||
// TODO(liuli): Improve it.
|
||||
uintptr_t LinuxThread::GetThreadStackBottom(uintptr_t current_ebp) const { |
||||
void **sp = reinterpret_cast<void **>(current_ebp); |
||||
void **previous_sp = sp; |
||||
while (sp && IsAddressMapped((uintptr_t)sp)) { |
||||
previous_sp = sp; |
||||
sp = reinterpret_cast<void **>(GetNextFrame(sp)); |
||||
} |
||||
return (uintptr_t)previous_sp; |
||||
} |
||||
|
||||
int LinuxThread::GetModuleCount() const { |
||||
return ListModules(NULL); |
||||
} |
||||
|
||||
int LinuxThread::ListModules( |
||||
CallbackParam<ModuleCallback> *callback_param) const { |
||||
char line[512]; |
||||
const char *maps_path = "/proc/self/maps"; |
||||
|
||||
int module_count = 0; |
||||
FILE *fp = fopen(maps_path, "r"); |
||||
if (fp == NULL) |
||||
return -1; |
||||
|
||||
uintptr_t start_addr; |
||||
uintptr_t end_addr; |
||||
while (fgets(line, sizeof(line), fp) != NULL) { |
||||
if (sscanf(line, "%x-%x", &start_addr, &end_addr) == 2) { |
||||
ModuleInfo module; |
||||
memset(&module, 0, sizeof(module)); |
||||
module.start_addr = start_addr; |
||||
module.size = end_addr - start_addr; |
||||
char *name = NULL; |
||||
assert(module.size > 0); |
||||
// Only copy name if the name is a valid path name.
|
||||
if ((name = strchr(line, '/')) != NULL) { |
||||
// Get rid of the last '\n' in line
|
||||
char *last_return = strchr(line, '\n'); |
||||
if (last_return != NULL) |
||||
*last_return = '\0'; |
||||
// Keep a space for the ending 0.
|
||||
strncpy(module.name, name, sizeof(module.name) - 1); |
||||
++module_count; |
||||
} |
||||
if (callback_param && |
||||
!(callback_param->call_back(module, callback_param->context))) |
||||
break; |
||||
} |
||||
} |
||||
fclose(fp); |
||||
return module_count; |
||||
} |
||||
|
||||
// Parse /proc/$pid/tasks to list all the threads of the process identified by
|
||||
// pid.
|
||||
int LinuxThread::IterateProcSelfTask(int pid, |
||||
CallbackParam<PidCallback> *callback_param) const { |
||||
char task_path[80]; |
||||
FillProcPath(pid, task_path, sizeof(task_path)); |
||||
strcat(task_path, "task"); |
||||
|
||||
DIR *dir = opendir(task_path); |
||||
if (dir == NULL) |
||||
return -1; |
||||
|
||||
int pid_number = 0; |
||||
// Record the last pid we've found. This is used for duplicated thread
|
||||
// removal. Duplicated thread information can be found in /proc/$pid/tasks.
|
||||
int last_pid = -1; |
||||
struct dirent *entry = NULL; |
||||
while ((entry = readdir(dir)) != NULL) { |
||||
if (strcmp(entry->d_name, ".") && |
||||
strcmp(entry->d_name, "..")) { |
||||
int tpid = 0; |
||||
if (LocalAtoi(entry->d_name, &tpid) && |
||||
last_pid != tpid) { |
||||
last_pid = tpid; |
||||
++pid_number; |
||||
// Invoke the callback.
|
||||
if (callback_param && |
||||
!(callback_param->call_back)(tpid, callback_param->context)) |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
closedir(dir); |
||||
return pid_number; |
||||
} |
||||
|
||||
// Check if the address is a valid virtual address.
|
||||
// If the address is in any of the mapped modules, we take it as valid.
|
||||
// Otherwise it is invalid.
|
||||
bool LinuxThread::IsAddressMapped(uintptr_t address) const { |
||||
AddressValidatingContext addr; |
||||
addr.address = address; |
||||
CallbackParam<ModuleCallback> callback_param(IsAddressInModuleCallback, |
||||
&addr); |
||||
ListModules(&callback_param); |
||||
return addr.is_mapped; |
||||
} |
||||
|
||||
bool LinuxThread::FindSigContext(uintptr_t sighandler_ebp, |
||||
struct sigcontext **sig_ctx) { |
||||
uintptr_t previous_ebp; |
||||
const int MAX_STACK_DEPTH = 10; |
||||
int depth_counter = 0; |
||||
|
||||
do { |
||||
// We're looking for a |struct sigcontext| as the second parameter
|
||||
// to a signal handler function call. Luckily, the sigcontext
|
||||
// has an ebp member which should match the ebp pointed to
|
||||
// by the ebp of the signal handler frame.
|
||||
previous_ebp = reinterpret_cast<uintptr_t>(GetNextFrame( |
||||
reinterpret_cast<void**>(sighandler_ebp))); |
||||
// The stack looks like this:
|
||||
// | previous ebp | previous eip | first param | second param |,
|
||||
// so we need to offset by 3 to get to the second parameter.
|
||||
*sig_ctx = reinterpret_cast<struct sigcontext*>(sighandler_ebp + |
||||
3 * sizeof(uintptr_t)); |
||||
sighandler_ebp = previous_ebp; |
||||
depth_counter++; |
||||
} while(previous_ebp != (*sig_ctx)->ebp && sighandler_ebp != 0 && |
||||
IsAddressMapped(sighandler_ebp) && depth_counter < MAX_STACK_DEPTH); |
||||
|
||||
return previous_ebp == (*sig_ctx)->ebp && previous_ebp != 0; |
||||
} |
||||
|
||||
} // namespace google_breakpad
|
@ -0,0 +1,204 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Author: Li Liu
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
#ifndef CLIENT_LINUX_HANDLER_LINUX_THREAD_H__ |
||||
#define CLIENT_LINUX_HANDLER_LINUX_THREAD_H__ |
||||
|
||||
#include <stdint.h> |
||||
#include <sys/user.h> |
||||
|
||||
namespace google_breakpad { |
||||
|
||||
// Max module path name length.
|
||||
#define kMaxModuleNameLength 256 |
||||
|
||||
// Holding information about a thread in the process.
|
||||
struct ThreadInfo { |
||||
// Id of the thread group.
|
||||
int tgid; |
||||
// Id of the thread.
|
||||
int pid; |
||||
// Id of the parent process.
|
||||
int ppid; |
||||
}; |
||||
|
||||
// Holding infomaton about a module in the process.
|
||||
struct ModuleInfo { |
||||
char name[kMaxModuleNameLength]; |
||||
uintptr_t start_addr; |
||||
int size; |
||||
}; |
||||
|
||||
// Holding debug registers.
|
||||
struct DebugRegs { |
||||
int dr0; |
||||
int dr1; |
||||
int dr2; |
||||
int dr3; |
||||
int dr4; |
||||
int dr5; |
||||
int dr6; |
||||
int dr7; |
||||
}; |
||||
|
||||
// A callback to run when got a thread in the process.
|
||||
// Return true will go on to the next thread while return false will stop the
|
||||
// iteration.
|
||||
typedef bool (*ThreadCallback)(const ThreadInfo &thread_info, void *context); |
||||
|
||||
// A callback to run when a new module is found in the process.
|
||||
// Return true will go on to the next module while return false will stop the
|
||||
// iteration.
|
||||
typedef bool (*ModuleCallback)(const ModuleInfo &module_info, void *context); |
||||
|
||||
// Holding the callback information.
|
||||
template<class CallbackFunc> |
||||
struct CallbackParam { |
||||
// Callback function address.
|
||||
CallbackFunc call_back; |
||||
// Callback context;
|
||||
void *context; |
||||
|
||||
CallbackParam() : call_back(NULL), context(NULL) { |
||||
} |
||||
|
||||
CallbackParam(CallbackFunc func, void *func_context) : |
||||
call_back(func), context(func_context) { |
||||
} |
||||
}; |
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//
|
||||
// LinuxThread
|
||||
//
|
||||
// Provides handy support for operation on linux threads.
|
||||
// It uses ptrace to get thread registers. Since ptrace only works in a
|
||||
// different process other than the one being ptraced, user of this class
|
||||
// should create another process before using the class.
|
||||
//
|
||||
// The process should be created in the following way:
|
||||
// int cloned_pid = clone(ProcessEntryFunction, stack_address,
|
||||
// CLONE_VM | CLONE_FILES | CLONE_FS | CLONE_UNTRACED,
|
||||
// (void*)&arguments);
|
||||
// waitpid(cloned_pid, NULL, __WALL);
|
||||
//
|
||||
// If CLONE_VM is not used, GetThreadStackBottom, GetThreadStackDump
|
||||
// will not work since it just use memcpy to get the stack dump.
|
||||
//
|
||||
class LinuxThread { |
||||
public: |
||||
// Create a LinuxThread instance to list all the threads in a process.
|
||||
explicit LinuxThread(int pid); |
||||
~LinuxThread(); |
||||
|
||||
// Stop all the threads in the process.
|
||||
// Return the number of stopped threads in the process.
|
||||
// Return -1 means failed to stop threads.
|
||||
int SuspendAllThreads(); |
||||
|
||||
// Resume all the suspended threads.
|
||||
void ResumeAllThreads() const; |
||||
|
||||
// Get the count of threads in the process.
|
||||
// Return -1 means error.
|
||||
int GetThreadCount() const; |
||||
|
||||
// List the threads of process.
|
||||
// Whenever there is a thread found, the callback will be invoked to process
|
||||
// the information.
|
||||
// Return number of threads listed.
|
||||
int ListThreads(CallbackParam<ThreadCallback> *thread_callback_param) const; |
||||
|
||||
// Get the general purpose registers of a thread.
|
||||
// The caller must get the thread pid by ListThreads.
|
||||
bool GetRegisters(int pid, user_regs_struct *regs) const; |
||||
|
||||
// Get the floating-point registers of a thread.
|
||||
// The caller must get the thread pid by ListThreads.
|
||||
bool GetFPRegisters(int pid, user_fpregs_struct *regs) const; |
||||
|
||||
// Get all the extended floating-point registers. May not work on all
|
||||
// machines.
|
||||
// The caller must get the thread pid by ListThreads.
|
||||
bool GetFPXRegisters(int pid, user_fpxregs_struct *regs) const; |
||||
|
||||
// Get the debug registers.
|
||||
// The caller must get the thread pid by ListThreads.
|
||||
bool GetDebugRegisters(int pid, DebugRegs *regs) const; |
||||
|
||||
// Get the stack memory dump.
|
||||
int GetThreadStackDump(uintptr_t current_ebp, |
||||
uintptr_t current_esp, |
||||
void *buf, |
||||
int buf_size) const; |
||||
|
||||
// Get the module count of the current process.
|
||||
int GetModuleCount() const; |
||||
|
||||
// Get the mapped modules in the address space.
|
||||
// Whenever a module is found, the callback will be invoked to process the
|
||||
// information.
|
||||
// Return how may modules are found.
|
||||
int ListModules(CallbackParam<ModuleCallback> *callback_param) const; |
||||
|
||||
// Get the bottom of the stack from ebp.
|
||||
uintptr_t GetThreadStackBottom(uintptr_t current_ebp) const; |
||||
|
||||
// Finds a sigcontext on the stack given the ebp of our signal handler.
|
||||
bool FindSigContext(uintptr_t sighandler_ebp, struct sigcontext **sig_ctx); |
||||
|
||||
private: |
||||
// This callback will run when a new thread has been found.
|
||||
typedef bool (*PidCallback)(int pid, void *context); |
||||
|
||||
// Read thread information from /proc/$pid/task.
|
||||
// Whenever a thread has been found, and callback will be invoked with
|
||||
// the pid of the thread.
|
||||
// Return number of threads found.
|
||||
// Return -1 means the directory doesn't exist.
|
||||
int IterateProcSelfTask(int pid, |
||||
CallbackParam<PidCallback> *callback_param) const; |
||||
|
||||
// Check if the address is a valid virtual address.
|
||||
bool IsAddressMapped(uintptr_t address) const; |
||||
|
||||
private: |
||||
// The pid of the process we are listing threads.
|
||||
int pid_; |
||||
|
||||
// Mark if we have suspended the threads.
|
||||
bool threads_suspened_; |
||||
}; |
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // CLIENT_LINUX_HANDLER_LINUX_THREAD_H__
|
@ -0,0 +1,224 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Author: Li Liu
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <pthread.h> |
||||
#include <sys/types.h> |
||||
#include <unistd.h> |
||||
#include <sys/wait.h> |
||||
|
||||
#include <cstdio> |
||||
#include <cstdlib> |
||||
#include <cstring> |
||||
|
||||
#include "client/linux/handler/linux_thread.h" |
||||
|
||||
using namespace google_breakpad; |
||||
|
||||
// Thread use this to see if it should stop working.
|
||||
static bool should_exit = false; |
||||
|
||||
static void foo2(int *a) { |
||||
// Stack variable, used for debugging stack dumps.
|
||||
int c = 0xcccccccc; |
||||
c = c; |
||||
while (!should_exit) |
||||
sleep(1); |
||||
} |
||||
|
||||
static void foo() { |
||||
// Stack variable, used for debugging stack dumps.
|
||||
int a = 0xaaaaaaaa; |
||||
foo2(&a); |
||||
} |
||||
|
||||
static void *thread_main(void *) { |
||||
// Stack variable, used for debugging stack dumps.
|
||||
int b = 0xbbbbbbbb; |
||||
b = b; |
||||
while (!should_exit) { |
||||
foo(); |
||||
} |
||||
return NULL; |
||||
} |
||||
|
||||
static void CreateThreads(int num) { |
||||
pthread_t handle; |
||||
for (int i = 0; i < num; i++) { |
||||
if (0 != pthread_create(&handle, NULL, thread_main, NULL)) |
||||
fprintf(stderr, "Failed to create thread.\n"); |
||||
else |
||||
pthread_detach(handle); |
||||
} |
||||
} |
||||
|
||||
static bool ProcessOneModule(const struct ModuleInfo &module_info, |
||||
void *context) { |
||||
printf("0x%x[%8d] %s\n", module_info.start_addr, module_info.size, |
||||
module_info.name); |
||||
return true; |
||||
} |
||||
|
||||
static bool ProcessOneThread(const struct ThreadInfo &thread_info, |
||||
void *context) { |
||||
printf("\n\nPID: %d, TGID: %d, PPID: %d\n", |
||||
thread_info.pid, |
||||
thread_info.tgid, |
||||
thread_info.ppid); |
||||
|
||||
struct user_regs_struct regs; |
||||
struct user_fpregs_struct fp_regs; |
||||
struct user_fpxregs_struct fpx_regs; |
||||
struct DebugRegs dbg_regs; |
||||
|
||||
LinuxThread *threads = reinterpret_cast<LinuxThread *>(context); |
||||
memset(®s, 0, sizeof(regs)); |
||||
if (threads->GetRegisters(thread_info.pid, ®s)) { |
||||
printf(" gs = 0x%lx\n", regs.xgs); |
||||
printf(" fs = 0x%lx\n", regs.xfs); |
||||
printf(" es = 0x%lx\n", regs.xes); |
||||
printf(" ds = 0x%lx\n", regs.xds); |
||||
printf(" edi = 0x%lx\n", regs.edi); |
||||
printf(" esi = 0x%lx\n", regs.esi); |
||||
printf(" ebx = 0x%lx\n", regs.ebx); |
||||
printf(" edx = 0x%lx\n", regs.edx); |
||||
printf(" ecx = 0x%lx\n", regs.ecx); |
||||
printf(" eax = 0x%lx\n", regs.eax); |
||||
printf(" ebp = 0x%lx\n", regs.ebp); |
||||
printf(" eip = 0x%lx\n", regs.eip); |
||||
printf(" cs = 0x%lx\n", regs.xcs); |
||||
printf(" eflags = 0x%lx\n", regs.eflags); |
||||
printf(" esp = 0x%lx\n", regs.esp); |
||||
printf(" ss = 0x%lx\n", regs.xss); |
||||
} else { |
||||
fprintf(stderr, "ERROR: Failed to get general purpose registers\n"); |
||||
} |
||||
memset(&fp_regs, 0, sizeof(fp_regs)); |
||||
if (threads->GetFPRegisters(thread_info.pid, &fp_regs)) { |
||||
printf("\n Floating point registers:\n"); |
||||
printf(" fctl = 0x%lx\n", fp_regs.cwd); |
||||
printf(" fstat = 0x%lx\n", fp_regs.swd); |
||||
printf(" ftag = 0x%lx\n", fp_regs.twd); |
||||
printf(" fioff = 0x%lx\n", fp_regs.fip); |
||||
printf(" fiseg = 0x%lx\n", fp_regs.fcs); |
||||
printf(" fooff = 0x%lx\n", fp_regs.foo); |
||||
printf(" foseg = 0x%lx\n", fp_regs.fos); |
||||
int st_space_size = sizeof(fp_regs.st_space) / sizeof(fp_regs.st_space[0]); |
||||
printf(" st_space[%2d] = 0x", st_space_size); |
||||
for (int i = 0; i < st_space_size; ++i) |
||||
printf("%02lx", fp_regs.st_space[i]); |
||||
printf("\n"); |
||||
} else { |
||||
fprintf(stderr, "ERROR: Failed to get floating-point registers\n"); |
||||
} |
||||
memset(&fpx_regs, 0, sizeof(fpx_regs)); |
||||
if (threads->GetFPXRegisters(thread_info.pid, &fpx_regs)) { |
||||
printf("\n Extended floating point registers:\n"); |
||||
printf(" fctl = 0x%x\n", fpx_regs.cwd); |
||||
printf(" fstat = 0x%x\n", fpx_regs.swd); |
||||
printf(" ftag = 0x%x\n", fpx_regs.twd); |
||||
printf(" fioff = 0x%lx\n", fpx_regs.fip); |
||||
printf(" fiseg = 0x%lx\n", fpx_regs.fcs); |
||||
printf(" fooff = 0x%lx\n", fpx_regs.foo); |
||||
printf(" foseg = 0x%lx\n", fpx_regs.fos); |
||||
printf(" fop = 0x%x\n", fpx_regs.fop); |
||||
printf(" mxcsr = 0x%lx\n", fpx_regs.mxcsr); |
||||
int space_size = sizeof(fpx_regs.st_space) / sizeof(fpx_regs.st_space[0]); |
||||
printf(" st_space[%2d] = 0x", space_size); |
||||
for (int i = 0; i < space_size; ++i) |
||||
printf("%02lx", fpx_regs.st_space[i]); |
||||
printf("\n"); |
||||
space_size = sizeof(fpx_regs.xmm_space) / sizeof(fpx_regs.xmm_space[0]); |
||||
printf(" xmm_space[%2d] = 0x", space_size); |
||||
for (int i = 0; i < space_size; ++i) |
||||
printf("%02lx", fpx_regs.xmm_space[i]); |
||||
printf("\n"); |
||||
} |
||||
if (threads->GetDebugRegisters(thread_info.pid, &dbg_regs)) { |
||||
printf("\n Debug registers:\n"); |
||||
printf(" dr0 = 0x%x\n", dbg_regs.dr0); |
||||
printf(" dr1 = 0x%x\n", dbg_regs.dr1); |
||||
printf(" dr2 = 0x%x\n", dbg_regs.dr2); |
||||
printf(" dr3 = 0x%x\n", dbg_regs.dr3); |
||||
printf(" dr4 = 0x%x\n", dbg_regs.dr4); |
||||
printf(" dr5 = 0x%x\n", dbg_regs.dr5); |
||||
printf(" dr6 = 0x%x\n", dbg_regs.dr6); |
||||
printf(" dr7 = 0x%x\n", dbg_regs.dr7); |
||||
printf("\n"); |
||||
} |
||||
if (regs.esp != 0) { |
||||
// Print the stack content.
|
||||
int size = 1024 * 2; |
||||
char *buf = new char[size]; |
||||
size = threads->GetThreadStackDump(regs.ebp, |
||||
regs.esp, |
||||
(void*)buf, size); |
||||
printf(" Stack content: = 0x"); |
||||
size /= sizeof(unsigned long); |
||||
unsigned long *p_buf = (unsigned long *)(buf); |
||||
for (int i = 0; i < size; i += 1) |
||||
printf("%.8lx ", p_buf[i]); |
||||
delete []buf; |
||||
printf("\n"); |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
static int PrintAllThreads(void *argument) { |
||||
int pid = (int)argument; |
||||
|
||||
LinuxThread threads(pid); |
||||
int total_thread = threads.SuspendAllThreads(); |
||||
printf("There are %d threads in the process: %d\n", total_thread, pid); |
||||
int total_module = threads.GetModuleCount(); |
||||
printf("There are %d modules in the process: %d\n", total_module, pid); |
||||
CallbackParam<ModuleCallback> module_callback(ProcessOneModule, &threads); |
||||
threads.ListModules(&module_callback); |
||||
CallbackParam<ThreadCallback> thread_callback(ProcessOneThread, &threads); |
||||
threads.ListThreads(&thread_callback); |
||||
return 0; |
||||
} |
||||
|
||||
int main(int argc, char **argv) { |
||||
int pid = getpid(); |
||||
printf("Main thread is %d\n", pid); |
||||
CreateThreads(1); |
||||
// Create stack for the process.
|
||||
char *stack = new char[1024 * 100]; |
||||
int cloned_pid = clone(PrintAllThreads, stack + 1024 * 100, |
||||
CLONE_VM | CLONE_FILES | CLONE_FS | CLONE_UNTRACED, |
||||
(void*)getpid()); |
||||
waitpid(cloned_pid, NULL, __WALL); |
||||
should_exit = true; |
||||
printf("Test finished.\n"); |
||||
|
||||
delete []stack; |
||||
return 0; |
||||
} |
@ -0,0 +1,815 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Author: Li Liu
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <fcntl.h> |
||||
#include <pthread.h> |
||||
#include <signal.h> |
||||
#include <sys/stat.h> |
||||
#include <sys/types.h> |
||||
#include <unistd.h> |
||||
#include <sys/utsname.h> |
||||
#include <sys/wait.h> |
||||
|
||||
#include <cstdlib> |
||||
#include <ctime> |
||||
#include <string.h> |
||||
|
||||
#include "common/linux/file_id.h" |
||||
#include "client/linux/handler/linux_thread.h" |
||||
#include "client/minidump_file_writer.h" |
||||
#include "client/minidump_file_writer-inl.h" |
||||
#include "google_breakpad/common/minidump_format.h" |
||||
#include "client/linux/handler/minidump_generator.h" |
||||
|
||||
#ifndef CLONE_UNTRACED |
||||
#define CLONE_UNTRACED 0x00800000 |
||||
#endif |
||||
|
||||
// This unnamed namespace contains helper functions.
|
||||
namespace { |
||||
|
||||
using namespace google_breakpad; |
||||
|
||||
// Argument for the writer function.
|
||||
struct WriterArgument { |
||||
MinidumpFileWriter *minidump_writer; |
||||
|
||||
// Context for the callback.
|
||||
void *version_context; |
||||
|
||||
// Pid of the thread who called WriteMinidumpToFile
|
||||
int requester_pid; |
||||
|
||||
// The stack bottom of the thread which caused the dump.
|
||||
// Mainly used to find the thread id of the crashed thread since signal
|
||||
// handler may not be called in the thread who caused it.
|
||||
uintptr_t crashed_stack_bottom; |
||||
|
||||
// Pid of the crashing thread.
|
||||
int crashed_pid; |
||||
|
||||
// Signal number when crash happed. Can be 0 if this is a requested dump.
|
||||
int signo; |
||||
|
||||
// The ebp of the signal handler frame. Can be zero if this
|
||||
// is a requested dump.
|
||||
uintptr_t sighandler_ebp; |
||||
|
||||
// Signal context when crash happed. Can be NULL if this is a requested dump.
|
||||
// This is actually an out parameter, but it will be filled in at the start
|
||||
// of the writer thread.
|
||||
struct sigcontext *sig_ctx; |
||||
|
||||
// Used to get information about the threads.
|
||||
LinuxThread *thread_lister; |
||||
}; |
||||
|
||||
// Holding context information for the callback of finding the crashing thread.
|
||||
struct FindCrashThreadContext { |
||||
const LinuxThread *thread_lister; |
||||
uintptr_t crashing_stack_bottom; |
||||
int crashing_thread_pid; |
||||
|
||||
FindCrashThreadContext() : |
||||
thread_lister(NULL), |
||||
crashing_stack_bottom(0UL), |
||||
crashing_thread_pid(-1) { |
||||
} |
||||
}; |
||||
|
||||
// Callback for list threads.
|
||||
// It will compare the stack bottom of the provided thread with the stack
|
||||
// bottom of the crashed thread, it they are eqaul, this is thread is the one
|
||||
// who crashed.
|
||||
bool IsThreadCrashedCallback(const ThreadInfo &thread_info, void *context) { |
||||
FindCrashThreadContext *crashing_context = |
||||
static_cast<FindCrashThreadContext *>(context); |
||||
const LinuxThread *thread_lister = crashing_context->thread_lister; |
||||
struct user_regs_struct regs; |
||||
if (thread_lister->GetRegisters(thread_info.pid, ®s)) { |
||||
uintptr_t last_ebp = regs.ebp; |
||||
uintptr_t stack_bottom = thread_lister->GetThreadStackBottom(last_ebp); |
||||
if (stack_bottom > last_ebp && |
||||
stack_bottom == crashing_context->crashing_stack_bottom) { |
||||
// Got it. Stop iteration.
|
||||
crashing_context->crashing_thread_pid = thread_info.pid; |
||||
return false; |
||||
} |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
// Find the crashing thread id.
|
||||
// This is done based on stack bottom comparing.
|
||||
int FindCrashingThread(uintptr_t crashing_stack_bottom, |
||||
int requester_pid, |
||||
const LinuxThread *thread_lister) { |
||||
FindCrashThreadContext context; |
||||
context.thread_lister = thread_lister; |
||||
context.crashing_stack_bottom = crashing_stack_bottom; |
||||
CallbackParam<ThreadCallback> callback_param(IsThreadCrashedCallback, |
||||
&context); |
||||
thread_lister->ListThreads(&callback_param); |
||||
return context.crashing_thread_pid; |
||||
} |
||||
|
||||
// Write the thread stack info minidump.
|
||||
bool WriteThreadStack(uintptr_t last_ebp, |
||||
uintptr_t last_esp, |
||||
const LinuxThread *thread_lister, |
||||
UntypedMDRVA *memory, |
||||
MDMemoryDescriptor *loc) { |
||||
// Maximum stack size for a thread.
|
||||
uintptr_t stack_bottom = thread_lister->GetThreadStackBottom(last_ebp); |
||||
if (stack_bottom > last_esp) { |
||||
int size = stack_bottom - last_esp; |
||||
if (size > 0) { |
||||
if (!memory->Allocate(size)) |
||||
return false; |
||||
memory->Copy(reinterpret_cast<void*>(last_esp), size); |
||||
loc->start_of_memory_range = 0 | last_esp; |
||||
loc->memory = memory->location(); |
||||
} |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
// Write CPU context based on signal context.
|
||||
bool WriteContext(MDRawContextX86 *context, const struct sigcontext *sig_ctx, |
||||
const DebugRegs *debug_regs) { |
||||
assert(sig_ctx != NULL); |
||||
context->context_flags = MD_CONTEXT_X86_FULL; |
||||
context->gs = sig_ctx->gs; |
||||
context->fs = sig_ctx->fs; |
||||
context->es = sig_ctx->es; |
||||
context->ds = sig_ctx->ds; |
||||
context->cs = sig_ctx->cs; |
||||
context->ss = sig_ctx->ss; |
||||
context->edi = sig_ctx->edi; |
||||
context->esi = sig_ctx->esi; |
||||
context->ebp = sig_ctx->ebp; |
||||
context->esp = sig_ctx->esp; |
||||
context->ebx = sig_ctx->ebx; |
||||
context->edx = sig_ctx->edx; |
||||
context->ecx = sig_ctx->ecx; |
||||
context->eax = sig_ctx->eax; |
||||
context->eip = sig_ctx->eip; |
||||
context->eflags = sig_ctx->eflags; |
||||
if (sig_ctx->fpstate != NULL) { |
||||
context->context_flags = MD_CONTEXT_X86_FULL | |
||||
MD_CONTEXT_X86_FLOATING_POINT; |
||||
context->float_save.control_word = sig_ctx->fpstate->cw; |
||||
context->float_save.status_word = sig_ctx->fpstate->sw; |
||||
context->float_save.tag_word = sig_ctx->fpstate->tag; |
||||
context->float_save.error_offset = sig_ctx->fpstate->ipoff; |
||||
context->float_save.error_selector = sig_ctx->fpstate->cssel; |
||||
context->float_save.data_offset = sig_ctx->fpstate->dataoff; |
||||
context->float_save.data_selector = sig_ctx->fpstate->datasel; |
||||
memcpy(context->float_save.register_area, sig_ctx->fpstate->_st, |
||||
sizeof(context->float_save.register_area)); |
||||
} |
||||
|
||||
if (debug_regs != NULL) { |
||||
context->context_flags |= MD_CONTEXT_X86_DEBUG_REGISTERS; |
||||
context->dr0 = debug_regs->dr0; |
||||
context->dr1 = debug_regs->dr1; |
||||
context->dr2 = debug_regs->dr2; |
||||
context->dr3 = debug_regs->dr3; |
||||
context->dr6 = debug_regs->dr6; |
||||
context->dr7 = debug_regs->dr7; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
// Write CPU context based on provided registers.
|
||||
bool WriteContext(MDRawContextX86 *context, |
||||
const struct user_regs_struct *regs, |
||||
const struct user_fpregs_struct *fp_regs, |
||||
const DebugRegs *dbg_regs) { |
||||
if (!context || !regs) |
||||
return false; |
||||
|
||||
context->context_flags = MD_CONTEXT_X86_FULL; |
||||
|
||||
context->cs = regs->xcs; |
||||
context->ds = regs->xds; |
||||
context->es = regs->xes; |
||||
context->fs = regs->xfs; |
||||
context->gs = regs->xgs; |
||||
context->ss = regs->xss; |
||||
context->edi = regs->edi; |
||||
context->esi = regs->esi; |
||||
context->ebx = regs->ebx; |
||||
context->edx = regs->edx; |
||||
context->ecx = regs->ecx; |
||||
context->eax = regs->eax; |
||||
context->ebp = regs->ebp; |
||||
context->eip = regs->eip; |
||||
context->esp = regs->esp; |
||||
context->eflags = regs->eflags; |
||||
|
||||
if (dbg_regs != NULL) { |
||||
context->context_flags |= MD_CONTEXT_X86_DEBUG_REGISTERS; |
||||
context->dr0 = dbg_regs->dr0; |
||||
context->dr1 = dbg_regs->dr1; |
||||
context->dr2 = dbg_regs->dr2; |
||||
context->dr3 = dbg_regs->dr3; |
||||
context->dr6 = dbg_regs->dr6; |
||||
context->dr7 = dbg_regs->dr7; |
||||
} |
||||
|
||||
if (fp_regs != NULL) { |
||||
context->context_flags |= MD_CONTEXT_X86_FLOATING_POINT; |
||||
context->float_save.control_word = fp_regs->cwd; |
||||
context->float_save.status_word = fp_regs->swd; |
||||
context->float_save.tag_word = fp_regs->twd; |
||||
context->float_save.error_offset = fp_regs->fip; |
||||
context->float_save.error_selector = fp_regs->fcs; |
||||
context->float_save.data_offset = fp_regs->foo; |
||||
context->float_save.data_selector = fp_regs->fos; |
||||
context->float_save.data_selector = fp_regs->fos; |
||||
|
||||
memcpy(context->float_save.register_area, fp_regs->st_space, |
||||
sizeof(context->float_save.register_area)); |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
// Write information about a crashed thread.
|
||||
// When a thread crash, kernel will write something on the stack for processing
|
||||
// signal. This makes the current stack not reliable, and our stack walker
|
||||
// won't figure out the whole call stack for this. So we write the stack at the
|
||||
// time of the crash into the minidump file, not the current stack.
|
||||
bool WriteCrashedThreadStream(MinidumpFileWriter *minidump_writer, |
||||
const WriterArgument *writer_args, |
||||
const ThreadInfo &thread_info, |
||||
MDRawThread *thread) { |
||||
assert(writer_args->sig_ctx != NULL); |
||||
|
||||
thread->thread_id = thread_info.pid; |
||||
|
||||
UntypedMDRVA memory(minidump_writer); |
||||
if (!WriteThreadStack(writer_args->sig_ctx->ebp, |
||||
writer_args->sig_ctx->esp, |
||||
writer_args->thread_lister, |
||||
&memory, |
||||
&thread->stack)) |
||||
return false; |
||||
|
||||
TypedMDRVA<MDRawContextX86> context(minidump_writer); |
||||
if (!context.Allocate()) |
||||
return false; |
||||
thread->thread_context = context.location(); |
||||
memset(context.get(), 0, sizeof(MDRawContextX86)); |
||||
return WriteContext(context.get(), writer_args->sig_ctx, NULL); |
||||
} |
||||
|
||||
// Write information about a thread.
|
||||
// This function only processes thread running normally at the crash.
|
||||
bool WriteThreadStream(MinidumpFileWriter *minidump_writer, |
||||
const LinuxThread *thread_lister, |
||||
const ThreadInfo &thread_info, |
||||
MDRawThread *thread) { |
||||
thread->thread_id = thread_info.pid; |
||||
|
||||
struct user_regs_struct regs; |
||||
memset(®s, 0, sizeof(regs)); |
||||
if (!thread_lister->GetRegisters(thread_info.pid, ®s)) { |
||||
perror(NULL); |
||||
return false; |
||||
} |
||||
|
||||
UntypedMDRVA memory(minidump_writer); |
||||
if (!WriteThreadStack(regs.ebp, |
||||
regs.esp, |
||||
thread_lister, |
||||
&memory, |
||||
&thread->stack)) |
||||
return false; |
||||
|
||||
struct user_fpregs_struct fp_regs; |
||||
DebugRegs dbg_regs; |
||||
memset(&fp_regs, 0, sizeof(fp_regs)); |
||||
// Get all the registers.
|
||||
thread_lister->GetFPRegisters(thread_info.pid, &fp_regs); |
||||
thread_lister->GetDebugRegisters(thread_info.pid, &dbg_regs); |
||||
|
||||
// Write context
|
||||
TypedMDRVA<MDRawContextX86> context(minidump_writer); |
||||
if (!context.Allocate()) |
||||
return false; |
||||
thread->thread_context = context.location(); |
||||
memset(context.get(), 0, sizeof(MDRawContextX86)); |
||||
return WriteContext(context.get(), ®s, &fp_regs, &dbg_regs); |
||||
} |
||||
|
||||
bool WriteCPUInformation(MDRawSystemInfo *sys_info) { |
||||
const char *proc_cpu_path = "/proc/cpuinfo"; |
||||
char line[128]; |
||||
char vendor_id[13]; |
||||
const char vendor_id_name[] = "vendor_id"; |
||||
const size_t vendor_id_name_length = sizeof(vendor_id_name) - 1; |
||||
|
||||
struct CpuInfoEntry { |
||||
const char *info_name; |
||||
int value; |
||||
} cpu_info_table[] = { |
||||
{ "processor", -1 }, |
||||
{ "model", 0 }, |
||||
{ "stepping", 0 }, |
||||
{ "cpuid level", 0 }, |
||||
{ NULL, -1 }, |
||||
}; |
||||
|
||||
memset(vendor_id, 0, sizeof(vendor_id)); |
||||
|
||||
FILE *fp = fopen(proc_cpu_path, "r"); |
||||
if (fp != NULL) { |
||||
while (fgets(line, sizeof(line), fp)) { |
||||
CpuInfoEntry *entry = &cpu_info_table[0]; |
||||
while (entry->info_name != NULL) { |
||||
if (!strncmp(line, entry->info_name, strlen(entry->info_name))) { |
||||
char *value = strchr(line, ':'); |
||||
value++; |
||||
if (value != NULL) |
||||
sscanf(value, " %d", &(entry->value)); |
||||
} |
||||
entry++; |
||||
} |
||||
|
||||
// special case for vendor_id
|
||||
if (!strncmp(line, vendor_id_name, vendor_id_name_length)) { |
||||
char *value = strchr(line, ':'); |
||||
if (value == NULL) |
||||
continue; |
||||
|
||||
value++; |
||||
while (*value && isspace(*value)) |
||||
value++; |
||||
if (*value) { |
||||
size_t length = strlen(value); |
||||
// we don't want the trailing newline
|
||||
if (value[length - 1] == '\n') |
||||
length--; |
||||
// ensure we have space for the value
|
||||
if (length < sizeof(vendor_id)) |
||||
strncpy(vendor_id, value, length); |
||||
} |
||||
} |
||||
} |
||||
fclose(fp); |
||||
} |
||||
|
||||
// /proc/cpuinfo contains cpu id, change it into number by adding one.
|
||||
cpu_info_table[0].value++; |
||||
|
||||
sys_info->number_of_processors = cpu_info_table[0].value; |
||||
sys_info->processor_level = cpu_info_table[3].value; |
||||
sys_info->processor_revision = cpu_info_table[1].value << 8 | |
||||
cpu_info_table[2].value; |
||||
|
||||
sys_info->processor_architecture = MD_CPU_ARCHITECTURE_UNKNOWN; |
||||
struct utsname uts; |
||||
if (uname(&uts) == 0) { |
||||
// Match i*86 and x86* as X86 architecture.
|
||||
if ((strstr(uts.machine, "x86") == uts.machine) || |
||||
(strlen(uts.machine) == 4 && |
||||
uts.machine[0] == 'i' && |
||||
uts.machine[2] == '8' && |
||||
uts.machine[3] == '6')) { |
||||
sys_info->processor_architecture = MD_CPU_ARCHITECTURE_X86; |
||||
if (vendor_id[0] != '\0') |
||||
memcpy(sys_info->cpu.x86_cpu_info.vendor_id, vendor_id, |
||||
sizeof(sys_info->cpu.x86_cpu_info.vendor_id)); |
||||
} |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
bool WriteOSInformation(MinidumpFileWriter *minidump_writer, |
||||
MDRawSystemInfo *sys_info) { |
||||
sys_info->platform_id = MD_OS_LINUX; |
||||
|
||||
struct utsname uts; |
||||
if (uname(&uts) == 0) { |
||||
char os_version[512]; |
||||
size_t space_left = sizeof(os_version); |
||||
memset(os_version, 0, space_left); |
||||
const char *os_info_table[] = { |
||||
uts.sysname, |
||||
uts.release, |
||||
uts.version, |
||||
uts.machine, |
||||
"GNU/Linux", |
||||
NULL |
||||
}; |
||||
for (const char **cur_os_info = os_info_table; |
||||
*cur_os_info != NULL; |
||||
cur_os_info++) { |
||||
if (cur_os_info != os_info_table && space_left > 1) { |
||||
strcat(os_version, " "); |
||||
space_left--; |
||||
} |
||||
if (space_left > strlen(*cur_os_info)) { |
||||
strcat(os_version, *cur_os_info); |
||||
space_left -= strlen(*cur_os_info); |
||||
} else { |
||||
break; |
||||
} |
||||
} |
||||
|
||||
MDLocationDescriptor location; |
||||
if (!minidump_writer->WriteString(os_version, 0, &location)) |
||||
return false; |
||||
sys_info->csd_version_rva = location.rva; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
// Callback context for get writting thread information.
|
||||
struct ThreadInfoCallbackCtx { |
||||
MinidumpFileWriter *minidump_writer; |
||||
const WriterArgument *writer_args; |
||||
TypedMDRVA<MDRawThreadList> *list; |
||||
int thread_index; |
||||
}; |
||||
|
||||
// Callback run for writing threads information in the process.
|
||||
bool ThreadInfomationCallback(const ThreadInfo &thread_info, |
||||
void *context) { |
||||
ThreadInfoCallbackCtx *callback_context = |
||||
static_cast<ThreadInfoCallbackCtx *>(context); |
||||
bool success = true; |
||||
MDRawThread thread; |
||||
memset(&thread, 0, sizeof(MDRawThread)); |
||||
if (thread_info.pid != callback_context->writer_args->crashed_pid || |
||||
callback_context->writer_args->sig_ctx == NULL) { |
||||
success = WriteThreadStream(callback_context->minidump_writer, |
||||
callback_context->writer_args->thread_lister, |
||||
thread_info, &thread); |
||||
} else { |
||||
success = WriteCrashedThreadStream(callback_context->minidump_writer, |
||||
callback_context->writer_args, |
||||
thread_info, &thread); |
||||
} |
||||
if (success) { |
||||
callback_context->list->CopyIndexAfterObject( |
||||
callback_context->thread_index++, |
||||
&thread, sizeof(MDRawThread)); |
||||
} |
||||
return success; |
||||
} |
||||
|
||||
// Stream writers
|
||||
bool WriteThreadListStream(MinidumpFileWriter *minidump_writer, |
||||
const WriterArgument *writer_args, |
||||
MDRawDirectory *dir) { |
||||
// Get the thread information.
|
||||
const LinuxThread *thread_lister = writer_args->thread_lister; |
||||
int thread_count = thread_lister->GetThreadCount(); |
||||
if (thread_count < 0) |
||||
return false; |
||||
TypedMDRVA<MDRawThreadList> list(minidump_writer); |
||||
if (!list.AllocateObjectAndArray(thread_count, sizeof(MDRawThread))) |
||||
return false; |
||||
dir->stream_type = MD_THREAD_LIST_STREAM; |
||||
dir->location = list.location(); |
||||
list.get()->number_of_threads = thread_count; |
||||
|
||||
ThreadInfoCallbackCtx context; |
||||
context.minidump_writer = minidump_writer; |
||||
context.writer_args = writer_args; |
||||
context.list = &list; |
||||
context.thread_index = 0; |
||||
CallbackParam<ThreadCallback> callback_param(ThreadInfomationCallback, |
||||
&context); |
||||
int written = thread_lister->ListThreads(&callback_param); |
||||
return written == thread_count; |
||||
} |
||||
|
||||
bool WriteCVRecord(MinidumpFileWriter *minidump_writer, |
||||
MDRawModule *module, |
||||
const char *module_path) { |
||||
TypedMDRVA<MDCVInfoPDB70> cv(minidump_writer); |
||||
|
||||
// Only return the last path component of the full module path
|
||||
const char *module_name = strrchr(module_path, '/'); |
||||
// Increment past the slash
|
||||
if (module_name) |
||||
++module_name; |
||||
else |
||||
module_name = "<Unknown>"; |
||||
|
||||
size_t module_name_length = strlen(module_name); |
||||
if (!cv.AllocateObjectAndArray(module_name_length + 1, sizeof(u_int8_t))) |
||||
return false; |
||||
if (!cv.CopyIndexAfterObject(0, const_cast<char *>(module_name), |
||||
module_name_length)) |
||||
return false; |
||||
|
||||
module->cv_record = cv.location(); |
||||
MDCVInfoPDB70 *cv_ptr = cv.get(); |
||||
memset(cv_ptr, 0, sizeof(MDCVInfoPDB70)); |
||||
cv_ptr->cv_signature = MD_CVINFOPDB70_SIGNATURE; |
||||
cv_ptr->age = 0; |
||||
|
||||
// Get the module identifier
|
||||
FileID file_id(module_path); |
||||
unsigned char identifier[16]; |
||||
|
||||
if (file_id.ElfFileIdentifier(identifier)) { |
||||
cv_ptr->signature.data1 = (uint32_t)identifier[0] << 24 | |
||||
(uint32_t)identifier[1] << 16 | (uint32_t)identifier[2] << 8 | |
||||
(uint32_t)identifier[3]; |
||||
cv_ptr->signature.data2 = (uint32_t)identifier[4] << 8 | identifier[5]; |
||||
cv_ptr->signature.data3 = (uint32_t)identifier[6] << 8 | identifier[7]; |
||||
cv_ptr->signature.data4[0] = identifier[8]; |
||||
cv_ptr->signature.data4[1] = identifier[9]; |
||||
cv_ptr->signature.data4[2] = identifier[10]; |
||||
cv_ptr->signature.data4[3] = identifier[11]; |
||||
cv_ptr->signature.data4[4] = identifier[12]; |
||||
cv_ptr->signature.data4[5] = identifier[13]; |
||||
cv_ptr->signature.data4[6] = identifier[14]; |
||||
cv_ptr->signature.data4[7] = identifier[15]; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
struct ModuleInfoCallbackCtx { |
||||
MinidumpFileWriter *minidump_writer; |
||||
const WriterArgument *writer_args; |
||||
TypedMDRVA<MDRawModuleList> *list; |
||||
int module_index; |
||||
}; |
||||
|
||||
bool ModuleInfoCallback(const ModuleInfo &module_info, |
||||
void *context) { |
||||
ModuleInfoCallbackCtx *callback_context = |
||||
static_cast<ModuleInfoCallbackCtx *>(context); |
||||
// Skip those modules without name, or those that are not modules.
|
||||
if (strlen(module_info.name) == 0 || |
||||
!strchr(module_info.name, '/')) |
||||
return true; |
||||
|
||||
MDRawModule module; |
||||
memset(&module, 0, sizeof(module)); |
||||
MDLocationDescriptor loc; |
||||
if (!callback_context->minidump_writer->WriteString(module_info.name, 0, |
||||
&loc)) |
||||
return false; |
||||
module.base_of_image = (u_int64_t)module_info.start_addr; |
||||
module.size_of_image = module_info.size; |
||||
module.module_name_rva = loc.rva; |
||||
|
||||
if (!WriteCVRecord(callback_context->minidump_writer, &module, |
||||
module_info.name)) |
||||
return false; |
||||
callback_context->list->CopyIndexAfterObject( |
||||
callback_context->module_index++, &module, MD_MODULE_SIZE); |
||||
return true; |
||||
} |
||||
|
||||
bool WriteModuleListStream(MinidumpFileWriter *minidump_writer, |
||||
const WriterArgument *writer_args, |
||||
MDRawDirectory *dir) { |
||||
TypedMDRVA<MDRawModuleList> list(minidump_writer); |
||||
int module_count = writer_args->thread_lister->GetModuleCount(); |
||||
if (module_count <= 0 || |
||||
!list.AllocateObjectAndArray(module_count, MD_MODULE_SIZE)) |
||||
return false; |
||||
dir->stream_type = MD_MODULE_LIST_STREAM; |
||||
dir->location = list.location(); |
||||
list.get()->number_of_modules = module_count; |
||||
ModuleInfoCallbackCtx context; |
||||
context.minidump_writer = minidump_writer; |
||||
context.writer_args = writer_args; |
||||
context.list = &list; |
||||
context.module_index = 0; |
||||
CallbackParam<ModuleCallback> callback(ModuleInfoCallback, &context); |
||||
return writer_args->thread_lister->ListModules(&callback) == module_count; |
||||
} |
||||
|
||||
bool WriteSystemInfoStream(MinidumpFileWriter *minidump_writer, |
||||
const WriterArgument *writer_args, |
||||
MDRawDirectory *dir) { |
||||
TypedMDRVA<MDRawSystemInfo> sys_info(minidump_writer); |
||||
if (!sys_info.Allocate()) |
||||
return false; |
||||
dir->stream_type = MD_SYSTEM_INFO_STREAM; |
||||
dir->location = sys_info.location(); |
||||
|
||||
return WriteCPUInformation(sys_info.get()) && |
||||
WriteOSInformation(minidump_writer, sys_info.get()); |
||||
} |
||||
|
||||
bool WriteExceptionStream(MinidumpFileWriter *minidump_writer, |
||||
const WriterArgument *writer_args, |
||||
MDRawDirectory *dir) { |
||||
// This happenes when this is not a crash, but a requested dump.
|
||||
if (writer_args->sig_ctx == NULL) |
||||
return false; |
||||
|
||||
TypedMDRVA<MDRawExceptionStream> exception(minidump_writer); |
||||
if (!exception.Allocate()) |
||||
return false; |
||||
|
||||
dir->stream_type = MD_EXCEPTION_STREAM; |
||||
dir->location = exception.location(); |
||||
exception.get()->thread_id = writer_args->crashed_pid; |
||||
exception.get()->exception_record.exception_code = writer_args->signo; |
||||
exception.get()->exception_record.exception_flags = 0; |
||||
if (writer_args->sig_ctx != NULL) { |
||||
exception.get()->exception_record.exception_address = |
||||
writer_args->sig_ctx->eip; |
||||
} else { |
||||
return true; |
||||
} |
||||
|
||||
// Write context of the exception.
|
||||
TypedMDRVA<MDRawContextX86> context(minidump_writer); |
||||
if (!context.Allocate()) |
||||
return false; |
||||
exception.get()->thread_context = context.location(); |
||||
memset(context.get(), 0, sizeof(MDRawContextX86)); |
||||
return WriteContext(context.get(), writer_args->sig_ctx, NULL); |
||||
} |
||||
|
||||
bool WriteMiscInfoStream(MinidumpFileWriter *minidump_writer, |
||||
const WriterArgument *writer_args, |
||||
MDRawDirectory *dir) { |
||||
TypedMDRVA<MDRawMiscInfo> info(minidump_writer); |
||||
if (!info.Allocate()) |
||||
return false; |
||||
|
||||
dir->stream_type = MD_MISC_INFO_STREAM; |
||||
dir->location = info.location(); |
||||
info.get()->size_of_info = sizeof(MDRawMiscInfo); |
||||
info.get()->flags1 = MD_MISCINFO_FLAGS1_PROCESS_ID; |
||||
info.get()->process_id = writer_args->requester_pid; |
||||
|
||||
return true; |
||||
} |
||||
|
||||
bool WriteBreakpadInfoStream(MinidumpFileWriter *minidump_writer, |
||||
const WriterArgument *writer_args, |
||||
MDRawDirectory *dir) { |
||||
TypedMDRVA<MDRawBreakpadInfo> info(minidump_writer); |
||||
if (!info.Allocate()) |
||||
return false; |
||||
|
||||
dir->stream_type = MD_BREAKPAD_INFO_STREAM; |
||||
dir->location = info.location(); |
||||
|
||||
info.get()->validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID | |
||||
MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID; |
||||
info.get()->dump_thread_id = getpid(); |
||||
info.get()->requesting_thread_id = writer_args->requester_pid; |
||||
return true; |
||||
} |
||||
|
||||
// Prototype of writer functions.
|
||||
typedef bool (*WriteStringFN)(MinidumpFileWriter *, |
||||
const WriterArgument *, |
||||
MDRawDirectory *); |
||||
|
||||
// Function table to writer a full minidump.
|
||||
WriteStringFN writers[] = { |
||||
WriteThreadListStream, |
||||
WriteModuleListStream, |
||||
WriteSystemInfoStream, |
||||
WriteExceptionStream, |
||||
WriteMiscInfoStream, |
||||
WriteBreakpadInfoStream, |
||||
}; |
||||
|
||||
// Will call each writer function in the writers table.
|
||||
// It runs in a different process from the crashing process, but sharing
|
||||
// the same address space. This enables it to use ptrace functions.
|
||||
int Write(void *argument) { |
||||
WriterArgument *writer_args = |
||||
static_cast<WriterArgument *>(argument); |
||||
|
||||
if (!writer_args->thread_lister->SuspendAllThreads()) |
||||
return -1; |
||||
|
||||
if (writer_args->sighandler_ebp != 0 && |
||||
writer_args->thread_lister->FindSigContext(writer_args->sighandler_ebp, |
||||
&writer_args->sig_ctx)) { |
||||
writer_args->crashed_stack_bottom = |
||||
writer_args->thread_lister->GetThreadStackBottom( |
||||
writer_args->sig_ctx->ebp); |
||||
int crashed_pid = FindCrashingThread(writer_args->crashed_stack_bottom, |
||||
writer_args->requester_pid, |
||||
writer_args->thread_lister); |
||||
if (crashed_pid > 0) |
||||
writer_args->crashed_pid = crashed_pid; |
||||
} |
||||
|
||||
|
||||
MinidumpFileWriter *minidump_writer = writer_args->minidump_writer; |
||||
TypedMDRVA<MDRawHeader> header(minidump_writer); |
||||
TypedMDRVA<MDRawDirectory> dir(minidump_writer); |
||||
if (!header.Allocate()) |
||||
return 0; |
||||
|
||||
int writer_count = sizeof(writers) / sizeof(writers[0]); |
||||
// Need directory space for all writers.
|
||||
if (!dir.AllocateArray(writer_count)) |
||||
return 0; |
||||
header.get()->signature = MD_HEADER_SIGNATURE; |
||||
header.get()->version = MD_HEADER_VERSION; |
||||
header.get()->time_date_stamp = time(NULL); |
||||
header.get()->stream_count = writer_count; |
||||
header.get()->stream_directory_rva = dir.position(); |
||||
|
||||
int dir_index = 0; |
||||
MDRawDirectory local_dir; |
||||
for (int i = 0; i < writer_count; ++i) { |
||||
if (writers[i](minidump_writer, writer_args, &local_dir)) |
||||
dir.CopyIndex(dir_index++, &local_dir); |
||||
} |
||||
|
||||
writer_args->thread_lister->ResumeAllThreads(); |
||||
return 0; |
||||
} |
||||
|
||||
} // namespace
|
||||
|
||||
namespace google_breakpad { |
||||
|
||||
MinidumpGenerator::MinidumpGenerator() { |
||||
AllocateStack(); |
||||
} |
||||
|
||||
MinidumpGenerator::~MinidumpGenerator() { |
||||
} |
||||
|
||||
void MinidumpGenerator::AllocateStack() { |
||||
stack_.reset(new char[kStackSize]); |
||||
} |
||||
|
||||
bool MinidumpGenerator::WriteMinidumpToFile(const char *file_pathname, |
||||
int signo, |
||||
uintptr_t sighandler_ebp, |
||||
struct sigcontext **sig_ctx) const { |
||||
assert(file_pathname != NULL); |
||||
assert(stack_ != NULL); |
||||
|
||||
if (stack_ == NULL || file_pathname == NULL) |
||||
return false; |
||||
|
||||
MinidumpFileWriter minidump_writer; |
||||
if (minidump_writer.Open(file_pathname)) { |
||||
WriterArgument argument; |
||||
memset(&argument, 0, sizeof(argument)); |
||||
LinuxThread thread_lister(getpid()); |
||||
argument.thread_lister = &thread_lister; |
||||
argument.minidump_writer = &minidump_writer; |
||||
argument.requester_pid = getpid(); |
||||
argument.crashed_pid = getpid(); |
||||
argument.signo = signo; |
||||
argument.sighandler_ebp = sighandler_ebp; |
||||
argument.sig_ctx = NULL; |
||||
|
||||
int cloned_pid = clone(Write, stack_.get() + kStackSize, |
||||
CLONE_VM | CLONE_FILES | CLONE_FS | CLONE_UNTRACED, |
||||
(void*)&argument); |
||||
waitpid(cloned_pid, NULL, __WALL); |
||||
if (sig_ctx != NULL) |
||||
*sig_ctx = argument.sig_ctx; |
||||
return true; |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
} // namespace google_breakpad
|
@ -0,0 +1,73 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Author: Li Liu
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef CLIENT_LINUX_HANDLER_MINIDUMP_GENERATOR_H__ |
||||
#define CLIENT_LINUX_HANDLER_MINIDUMP_GENERATOR_H__ |
||||
|
||||
#include <stdint.h> |
||||
|
||||
#include "google_breakpad/common/breakpad_types.h" |
||||
#include "processor/scoped_ptr.h" |
||||
|
||||
struct sigcontext; |
||||
|
||||
namespace google_breakpad { |
||||
|
||||
//
|
||||
// MinidumpGenerator
|
||||
//
|
||||
// Write a minidump to file based on the signo and sig_ctx.
|
||||
// A minidump generator should be created before any exception happen.
|
||||
//
|
||||
class MinidumpGenerator { |
||||
public: |
||||
MinidumpGenerator(); |
||||
|
||||
~MinidumpGenerator(); |
||||
|
||||
// Write minidump.
|
||||
bool WriteMinidumpToFile(const char *file_pathname, |
||||
int signo, |
||||
uintptr_t sighandler_ebp, |
||||
struct sigcontext **sig_ctx) const; |
||||
private: |
||||
// Allocate memory for stack.
|
||||
void AllocateStack(); |
||||
|
||||
private: |
||||
// Stack size of the writer thread.
|
||||
static const int kStackSize = 1024 * 1024; |
||||
scoped_array<char> stack_; |
||||
}; |
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // CLIENT_LINUX_HANDLER_MINIDUMP_GENERATOR_H__
|
@ -0,0 +1,86 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Author: Li Liu
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <pthread.h> |
||||
#include <unistd.h> |
||||
|
||||
#include <cassert> |
||||
#include <cstdio> |
||||
#include <cstdlib> |
||||
#include <cstring> |
||||
|
||||
#include "client/linux/handler/minidump_generator.h" |
||||
|
||||
using namespace google_breakpad; |
||||
|
||||
// Thread use this to see if it should stop working.
|
||||
static bool should_exit = false; |
||||
|
||||
static void foo2(int arg) { |
||||
// Stack variable, used for debugging stack dumps.
|
||||
int c = arg; |
||||
c = 0xcccccccc; |
||||
while (!should_exit) |
||||
sleep(1); |
||||
} |
||||
|
||||
static void foo(int arg) { |
||||
// Stack variable, used for debugging stack dumps.
|
||||
int b = arg; |
||||
b = 0xbbbbbbbb; |
||||
foo2(b); |
||||
} |
||||
|
||||
static void *thread_main(void *) { |
||||
// Stack variable, used for debugging stack dumps.
|
||||
int a = 0xaaaaaaaa; |
||||
foo(a); |
||||
return NULL; |
||||
} |
||||
|
||||
static void CreateThread(int num) { |
||||
pthread_t h; |
||||
for (int i = 0; i < num; ++i) { |
||||
pthread_create(&h, NULL, thread_main, NULL); |
||||
pthread_detach(h); |
||||
} |
||||
} |
||||
|
||||
int main(int argc, char *argv[]) { |
||||
CreateThread(10); |
||||
google_breakpad::MinidumpGenerator mg; |
||||
if (mg.WriteMinidumpToFile("minidump_test.out", -1, 0, NULL)) |
||||
printf("Succeeded written minidump\n"); |
||||
else |
||||
printf("Failed to write minidump\n"); |
||||
should_exit = true; |
||||
return 0; |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,258 @@ |
||||
#ifndef _exc_user_ |
||||
#define _exc_user_ |
||||
|
||||
/* Module exc */ |
||||
|
||||
#include <string.h> |
||||
#include <mach/ndr.h> |
||||
#include <mach/boolean.h> |
||||
#include <mach/kern_return.h> |
||||
#include <mach/notify.h> |
||||
#include <mach/mach_types.h> |
||||
#include <mach/message.h> |
||||
#include <mach/mig_errors.h> |
||||
#include <mach/port.h> |
||||
|
||||
#ifdef AUTOTEST |
||||
#ifndef FUNCTION_PTR_T |
||||
#define FUNCTION_PTR_T |
||||
typedef void (*function_ptr_t)(mach_port_t, char *, mach_msg_type_number_t); |
||||
typedef struct { |
||||
char *name; |
||||
function_ptr_t function; |
||||
} function_table_entry; |
||||
typedef function_table_entry *function_table_t; |
||||
#endif /* FUNCTION_PTR_T */ |
||||
#endif /* AUTOTEST */ |
||||
|
||||
#ifndef exc_MSG_COUNT |
||||
#define exc_MSG_COUNT 3 |
||||
#endif /* exc_MSG_COUNT */ |
||||
|
||||
#include <mach/std_types.h> |
||||
#include <mach/mig.h> |
||||
#include <mach/mig.h> |
||||
#include <mach/mach_types.h> |
||||
|
||||
#ifdef __BeforeMigUserHeader |
||||
__BeforeMigUserHeader |
||||
#endif /* __BeforeMigUserHeader */ |
||||
|
||||
#include <sys/cdefs.h> |
||||
__BEGIN_DECLS |
||||
|
||||
|
||||
/* Routine exception_raise */ |
||||
#ifdef mig_external |
||||
mig_external |
||||
#else |
||||
extern |
||||
#endif /* mig_external */ |
||||
kern_return_t exception_raise |
||||
( |
||||
mach_port_t exception_port, |
||||
mach_port_t thread, |
||||
mach_port_t task, |
||||
exception_type_t exception, |
||||
exception_data_t code, |
||||
mach_msg_type_number_t codeCnt |
||||
); |
||||
|
||||
/* Routine exception_raise_state */ |
||||
#ifdef mig_external |
||||
mig_external |
||||
#else |
||||
extern |
||||
#endif /* mig_external */ |
||||
kern_return_t exception_raise_state |
||||
( |
||||
mach_port_t exception_port, |
||||
exception_type_t exception, |
||||
const exception_data_t code, |
||||
mach_msg_type_number_t codeCnt, |
||||
int *flavor, |
||||
const thread_state_t old_state, |
||||
mach_msg_type_number_t old_stateCnt, |
||||
thread_state_t new_state, |
||||
mach_msg_type_number_t *new_stateCnt |
||||
); |
||||
|
||||
/* Routine exception_raise_state_identity */ |
||||
#ifdef mig_external |
||||
mig_external |
||||
#else |
||||
extern |
||||
#endif /* mig_external */ |
||||
kern_return_t exception_raise_state_identity |
||||
( |
||||
mach_port_t exception_port, |
||||
mach_port_t thread, |
||||
mach_port_t task, |
||||
exception_type_t exception, |
||||
exception_data_t code, |
||||
mach_msg_type_number_t codeCnt, |
||||
int *flavor, |
||||
thread_state_t old_state, |
||||
mach_msg_type_number_t old_stateCnt, |
||||
thread_state_t new_state, |
||||
mach_msg_type_number_t *new_stateCnt |
||||
); |
||||
|
||||
__END_DECLS |
||||
|
||||
/********************** Caution **************************/ |
||||
/* The following data types should be used to calculate */ |
||||
/* maximum message sizes only. The actual message may be */ |
||||
/* smaller, and the position of the arguments within the */ |
||||
/* message layout may vary from what is presented here. */ |
||||
/* For example, if any of the arguments are variable- */ |
||||
/* sized, and less than the maximum is sent, the data */ |
||||
/* will be packed tight in the actual message to reduce */ |
||||
/* the presence of holes. */ |
||||
/********************** Caution **************************/ |
||||
|
||||
/* typedefs for all requests */ |
||||
|
||||
#ifndef __Request__exc_subsystem__defined |
||||
#define __Request__exc_subsystem__defined |
||||
|
||||
#ifdef __MigPackStructs |
||||
#pragma pack(4) |
||||
#endif |
||||
typedef struct { |
||||
mach_msg_header_t Head; |
||||
/* start of the kernel processed data */ |
||||
mach_msg_body_t msgh_body; |
||||
mach_msg_port_descriptor_t thread; |
||||
mach_msg_port_descriptor_t task; |
||||
/* end of the kernel processed data */ |
||||
NDR_record_t NDR; |
||||
exception_type_t exception; |
||||
mach_msg_type_number_t codeCnt; |
||||
integer_t code[2]; |
||||
} __Request__exception_raise_t; |
||||
#ifdef __MigPackStructs |
||||
#pragma pack() |
||||
#endif |
||||
|
||||
#ifdef __MigPackStructs |
||||
#pragma pack(4) |
||||
#endif |
||||
typedef struct { |
||||
mach_msg_header_t Head; |
||||
NDR_record_t NDR; |
||||
exception_type_t exception; |
||||
mach_msg_type_number_t codeCnt; |
||||
integer_t code[2]; |
||||
int flavor; |
||||
mach_msg_type_number_t old_stateCnt; |
||||
natural_t old_state[144]; |
||||
} __Request__exception_raise_state_t; |
||||
#ifdef __MigPackStructs |
||||
#pragma pack() |
||||
#endif |
||||
|
||||
#ifdef __MigPackStructs |
||||
#pragma pack(4) |
||||
#endif |
||||
typedef struct { |
||||
mach_msg_header_t Head; |
||||
/* start of the kernel processed data */ |
||||
mach_msg_body_t msgh_body; |
||||
mach_msg_port_descriptor_t thread; |
||||
mach_msg_port_descriptor_t task; |
||||
/* end of the kernel processed data */ |
||||
NDR_record_t NDR; |
||||
exception_type_t exception; |
||||
mach_msg_type_number_t codeCnt; |
||||
integer_t code[2]; |
||||
int flavor; |
||||
mach_msg_type_number_t old_stateCnt; |
||||
natural_t old_state[144]; |
||||
} __Request__exception_raise_state_identity_t; |
||||
#ifdef __MigPackStructs |
||||
#pragma pack() |
||||
#endif |
||||
#endif /* !__Request__exc_subsystem__defined */ |
||||
|
||||
/* union of all requests */ |
||||
|
||||
#ifndef __RequestUnion__exc_subsystem__defined |
||||
#define __RequestUnion__exc_subsystem__defined |
||||
union __RequestUnion__exc_subsystem { |
||||
__Request__exception_raise_t Request_exception_raise; |
||||
__Request__exception_raise_state_t Request_exception_raise_state; |
||||
__Request__exception_raise_state_identity_t Request_exception_raise_state_identity; |
||||
}; |
||||
#endif /* !__RequestUnion__exc_subsystem__defined */ |
||||
/* typedefs for all replies */ |
||||
|
||||
#ifndef __Reply__exc_subsystem__defined |
||||
#define __Reply__exc_subsystem__defined |
||||
|
||||
#ifdef __MigPackStructs |
||||
#pragma pack(4) |
||||
#endif |
||||
typedef struct { |
||||
mach_msg_header_t Head; |
||||
NDR_record_t NDR; |
||||
kern_return_t RetCode; |
||||
} __Reply__exception_raise_t; |
||||
#ifdef __MigPackStructs |
||||
#pragma pack() |
||||
#endif |
||||
|
||||
#ifdef __MigPackStructs |
||||
#pragma pack(4) |
||||
#endif |
||||
typedef struct { |
||||
mach_msg_header_t Head; |
||||
NDR_record_t NDR; |
||||
kern_return_t RetCode; |
||||
int flavor; |
||||
mach_msg_type_number_t new_stateCnt; |
||||
natural_t new_state[144]; |
||||
} __Reply__exception_raise_state_t; |
||||
#ifdef __MigPackStructs |
||||
#pragma pack() |
||||
#endif |
||||
|
||||
#ifdef __MigPackStructs |
||||
#pragma pack(4) |
||||
#endif |
||||
typedef struct { |
||||
mach_msg_header_t Head; |
||||
NDR_record_t NDR; |
||||
kern_return_t RetCode; |
||||
int flavor; |
||||
mach_msg_type_number_t new_stateCnt; |
||||
natural_t new_state[144]; |
||||
} __Reply__exception_raise_state_identity_t; |
||||
#ifdef __MigPackStructs |
||||
#pragma pack() |
||||
#endif |
||||
#endif /* !__Reply__exc_subsystem__defined */ |
||||
|
||||
/* union of all replies */ |
||||
|
||||
#ifndef __ReplyUnion__exc_subsystem__defined |
||||
#define __ReplyUnion__exc_subsystem__defined |
||||
union __ReplyUnion__exc_subsystem { |
||||
__Reply__exception_raise_t Reply_exception_raise; |
||||
__Reply__exception_raise_state_t Reply_exception_raise_state; |
||||
__Reply__exception_raise_state_identity_t Reply_exception_raise_state_identity; |
||||
}; |
||||
#endif /* !__RequestUnion__exc_subsystem__defined */ |
||||
|
||||
#ifndef subsystem_to_name_map_exc |
||||
#define subsystem_to_name_map_exc \ |
||||
{ "exception_raise", 2401 },\
|
||||
{ "exception_raise_state", 2402 },\
|
||||
{ "exception_raise_state_identity", 2403 } |
||||
#endif |
||||
|
||||
#ifdef __AfterMigUserHeader |
||||
__AfterMigUserHeader |
||||
#endif /* __AfterMigUserHeader */ |
||||
|
||||
#endif /* _exc_user_ */ |
@ -0,0 +1,381 @@ |
||||
/*
|
||||
* Copyright (c) 1999 Apple Computer, Inc. All rights reserved. |
||||
* |
||||
* @APPLE_LICENSE_HEADER_START@ |
||||
*
|
||||
* This file contains Original Code and/or Modifications of Original Code |
||||
* as defined in and that are subject to the Apple Public Source License |
||||
* Version 2.0 (the 'License'). You may not use this file except in |
||||
* compliance with the License. Please obtain a copy of the License at |
||||
* http://www.opensource.apple.com/apsl/ and read it before using this
|
||||
* file. |
||||
*
|
||||
* The Original Code and all software distributed under the License are |
||||
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER |
||||
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
||||
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, |
||||
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. |
||||
* Please see the License for the specific language governing rights and |
||||
* limitations under the License. |
||||
*
|
||||
* @APPLE_LICENSE_HEADER_END@ |
||||
*/ |
||||
/*
|
||||
* Copyright (c) 1989, 1993 |
||||
* The Regents of the University of California. All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions |
||||
* are met: |
||||
* 1. Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* 2. Redistributions in binary form must reproduce the above copyright |
||||
* notice, this list of conditions and the following disclaimer in the |
||||
* documentation and/or other materials provided with the distribution. |
||||
* 3. All advertising materials mentioning features or use of this software |
||||
* must display the following acknowledgement: |
||||
* This product includes software developed by the University of |
||||
* California, Berkeley and its contributors. |
||||
* 4. Neither the name of the University nor the names of its contributors |
||||
* may be used to endorse or promote products derived from this software |
||||
* without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
||||
* SUCH DAMAGE. |
||||
*/ |
||||
|
||||
|
||||
/* nealsid:
|
||||
* This file was copied from libc/gen/nlist.c from Darwin's source code
|
||||
* The version of nlist used as a base is from 10.5.2, libc-498
|
||||
* http://www.opensource.apple.com/darwinsource/10.5.2/Libc-498/gen/nlist.c
|
||||
*
|
||||
* The full tarball is at:
|
||||
* http://www.opensource.apple.com/darwinsource/tarballs/apsl/Libc-498.tar.gz
|
||||
*
|
||||
* I've modified it to be compatible with 64-bit images. However, |
||||
* 32-bit compatibility has not been retained.
|
||||
*/ |
||||
|
||||
#ifdef __LP64__ |
||||
|
||||
#include <mach-o/nlist.h> |
||||
#include <mach-o/loader.h> |
||||
#include <mach-o/fat.h> |
||||
#include <stdlib.h> |
||||
#include <fcntl.h> |
||||
#include <sys/types.h> |
||||
#include <sys/uio.h> |
||||
#include <unistd.h> |
||||
#include "breakpad_nlist_64.h" |
||||
#include <TargetConditionals.h> |
||||
#include <stdio.h> |
||||
#include <mach/mach.h> |
||||
|
||||
/* Stuff lifted from <a.out.h> and <sys/exec.h> since they are gone */ |
||||
/*
|
||||
* Header prepended to each a.out file. |
||||
*/ |
||||
struct exec { |
||||
unsigned short a_machtype; /* machine type */ |
||||
unsigned short a_magic; /* magic number */ |
||||
unsigned long a_text; /* size of text segment */ |
||||
unsigned long a_data; /* size of initialized data */ |
||||
unsigned long a_bss; /* size of uninitialized data */ |
||||
unsigned long a_syms; /* size of symbol table */ |
||||
unsigned long a_entry; /* entry point */ |
||||
unsigned long a_trsize; /* size of text relocation */ |
||||
unsigned long a_drsize; /* size of data relocation */ |
||||
}; |
||||
|
||||
#define OMAGIC 0407 /* old impure format */ |
||||
#define NMAGIC 0410 /* read-only text */ |
||||
#define ZMAGIC 0413 /* demand load format */ |
||||
|
||||
#define N_BADMAG(x) \ |
||||
(((x).a_magic)!=OMAGIC && ((x).a_magic)!=NMAGIC && ((x).a_magic)!=ZMAGIC) |
||||
#define N_TXTOFF(x) \ |
||||
((x).a_magic==ZMAGIC ? 0 : sizeof (struct exec)) |
||||
#define N_SYMOFF(x) \ |
||||
(N_TXTOFF(x) + (x).a_text+(x).a_data + (x).a_trsize+(x).a_drsize) |
||||
|
||||
int |
||||
__breakpad_fdnlist_64(int fd, breakpad_nlist *list, const char **symbolNames); |
||||
|
||||
/*
|
||||
* nlist - retreive attributes from name list (string table version) |
||||
*/ |
||||
|
||||
int |
||||
breakpad_nlist_64(const char *name, |
||||
breakpad_nlist *list, |
||||
const char **symbolNames) { |
||||
int fd, n; |
||||
|
||||
fd = open(name, O_RDONLY, 0); |
||||
if (fd < 0) |
||||
return (-1); |
||||
n = __breakpad_fdnlist_64(fd, list, symbolNames); |
||||
(void)close(fd); |
||||
return (n); |
||||
} |
||||
|
||||
/* Note: __fdnlist() is called from kvm_nlist in libkvm's kvm.c */ |
||||
|
||||
int |
||||
__breakpad_fdnlist_64(int fd, breakpad_nlist *list, const char **symbolNames) { |
||||
register breakpad_nlist *p, *q; |
||||
breakpad_nlist space[BUFSIZ/sizeof (breakpad_nlist)]; |
||||
|
||||
const register char *s1, *s2; |
||||
register int n, m; |
||||
int maxlen, nreq; |
||||
off_t sa; /* symbol address */ |
||||
off_t ss; /* start of strings */ |
||||
struct exec buf; |
||||
unsigned arch_offset = 0; |
||||
|
||||
maxlen = 500; |
||||
for (q = list, nreq = 0; |
||||
symbolNames[q-list] && symbolNames[q-list][0]; |
||||
q++, nreq++) { |
||||
|
||||
q->n_type = 0; |
||||
q->n_value = 0; |
||||
q->n_desc = 0; |
||||
q->n_sect = 0; |
||||
q->n_un.n_strx = 0; |
||||
} |
||||
|
||||
if (read(fd, (char *)&buf, sizeof(buf)) != sizeof(buf) || |
||||
(N_BADMAG(buf) && *((long *)&buf) != MH_MAGIC && |
||||
NXSwapBigLongToHost(*((long *)&buf)) != FAT_MAGIC) && |
||||
/* nealsid: The following is the big-endian ppc64 check */ |
||||
(*((uint32_t*)&buf)) != FAT_MAGIC) { |
||||
return (-1); |
||||
} |
||||
|
||||
/* Deal with fat file if necessary */ |
||||
if (NXSwapBigLongToHost(*((long *)&buf)) == FAT_MAGIC || |
||||
/* nealsid: The following is the big-endian ppc64 check */ |
||||
*((int*)&buf) == FAT_MAGIC) { |
||||
struct host_basic_info hbi; |
||||
struct fat_header fh; |
||||
struct fat_arch *fat_archs, *fap; |
||||
unsigned i; |
||||
host_t host; |
||||
|
||||
/* Get our host info */ |
||||
host = mach_host_self(); |
||||
i = HOST_BASIC_INFO_COUNT; |
||||
kern_return_t kr; |
||||
if ((kr=host_info(host, HOST_BASIC_INFO, |
||||
(host_info_t)(&hbi), &i)) != KERN_SUCCESS) { |
||||
return (-1); |
||||
} |
||||
mach_port_deallocate(mach_task_self(), host); |
||||
|
||||
/* Read in the fat header */ |
||||
lseek(fd, 0, SEEK_SET); |
||||
if (read(fd, (char *)&fh, sizeof(fh)) != sizeof(fh)) { |
||||
return (-1); |
||||
} |
||||
|
||||
/* Convert fat_narchs to host byte order */ |
||||
fh.nfat_arch = NXSwapBigLongToHost(fh.nfat_arch); |
||||
|
||||
/* Read in the fat archs */ |
||||
fat_archs = (struct fat_arch *)malloc(fh.nfat_arch * |
||||
sizeof(struct fat_arch)); |
||||
if (fat_archs == NULL) { |
||||
return (-1); |
||||
} |
||||
if (read(fd, (char *)fat_archs, |
||||
sizeof(struct fat_arch) * fh.nfat_arch) != |
||||
sizeof(struct fat_arch) * fh.nfat_arch) { |
||||
free(fat_archs); |
||||
return (-1); |
||||
} |
||||
|
||||
/*
|
||||
* Convert archs to host byte ordering (a constraint of |
||||
* cpusubtype_getbestarch() |
||||
*/ |
||||
for (i = 0; i < fh.nfat_arch; i++) { |
||||
fat_archs[i].cputype = |
||||
NXSwapBigLongToHost(fat_archs[i].cputype); |
||||
fat_archs[i].cpusubtype = |
||||
NXSwapBigLongToHost(fat_archs[i].cpusubtype); |
||||
fat_archs[i].offset = |
||||
NXSwapBigLongToHost(fat_archs[i].offset); |
||||
fat_archs[i].size = |
||||
NXSwapBigLongToHost(fat_archs[i].size); |
||||
fat_archs[i].align = |
||||
NXSwapBigLongToHost(fat_archs[i].align); |
||||
} |
||||
|
||||
fap = NULL; |
||||
for (i = 0; i < fh.nfat_arch; i++) { |
||||
/* nealsid: Although the original Apple code uses host_info */ |
||||
/* to retrieve the CPU type, the host_info will still return */ |
||||
/* CPU_TYPE_X86 even if running as an x86_64 binary. Given that */ |
||||
/* this code isn't necessary on i386, I've decided to hardcode */ |
||||
/* looking for a 64-bit binary */ |
||||
#if TARGET_CPU_X86_64 |
||||
if (fat_archs[i].cputype == CPU_TYPE_X86_64) { |
||||
#elif TARGET_CPU_PPC64 |
||||
if (fat_archs[i].cputype == CPU_TYPE_POWERPC64) { |
||||
#else |
||||
#error undefined cpu! |
||||
{ |
||||
#endif |
||||
fap = &fat_archs[i]; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
if (!fap) { |
||||
free(fat_archs); |
||||
return (-1); |
||||
} |
||||
arch_offset = fap->offset; |
||||
free(fat_archs); |
||||
|
||||
/* Read in the beginning of the architecture-specific file */ |
||||
lseek(fd, arch_offset, SEEK_SET); |
||||
if (read(fd, (char *)&buf, sizeof(buf)) != sizeof(buf)) { |
||||
return (-1); |
||||
} |
||||
} |
||||
|
||||
if (*((int *)&buf) == MH_MAGIC_64) { |
||||
struct mach_header_64 mh; |
||||
struct load_command *load_commands, *lcp; |
||||
struct symtab_command *stp; |
||||
long i; |
||||
|
||||
lseek(fd, arch_offset, SEEK_SET); |
||||
if (read(fd, (char *)&mh, sizeof(mh)) != sizeof(mh)) { |
||||
return (-1); |
||||
} |
||||
load_commands = (struct load_command *)malloc(mh.sizeofcmds); |
||||
if (load_commands == NULL) { |
||||
return (-1); |
||||
} |
||||
if (read(fd, (char *)load_commands, mh.sizeofcmds) != |
||||
mh.sizeofcmds) { |
||||
free(load_commands); |
||||
return (-1); |
||||
} |
||||
stp = NULL; |
||||
lcp = load_commands; |
||||
// nealsid:iterate through all load commands, looking for
|
||||
// LC_SYMTAB load command
|
||||
for (i = 0; i < mh.ncmds; i++) { |
||||
if (lcp->cmdsize % sizeof(long) != 0 || |
||||
lcp->cmdsize <= 0 || |
||||
(char *)lcp + lcp->cmdsize > |
||||
(char *)load_commands + mh.sizeofcmds) { |
||||
free(load_commands); |
||||
return (-1); |
||||
} |
||||
if (lcp->cmd == LC_SYMTAB) { |
||||
if (lcp->cmdsize != |
||||
sizeof(struct symtab_command)) { |
||||
free(load_commands); |
||||
return (-1); |
||||
} |
||||
stp = (struct symtab_command *)lcp; |
||||
break; |
||||
} |
||||
lcp = (struct load_command *) |
||||
((char *)lcp + lcp->cmdsize); |
||||
} |
||||
if (stp == NULL) { |
||||
free(load_commands); |
||||
return (-1); |
||||
} |
||||
// sa points to the beginning of the symbol table
|
||||
sa = stp->symoff + arch_offset; |
||||
// ss points to the beginning of the string table
|
||||
ss = stp->stroff + arch_offset; |
||||
// n is the number of bytes in the symbol table
|
||||
// each symbol table entry is an nlist structure
|
||||
n = stp->nsyms * sizeof(breakpad_nlist); |
||||
free(load_commands); |
||||
} |
||||
else { |
||||
sa = N_SYMOFF(buf) + arch_offset; |
||||
ss = sa + buf.a_syms + arch_offset; |
||||
n = buf.a_syms; |
||||
} |
||||
|
||||
lseek(fd, sa, SEEK_SET); |
||||
|
||||
// the algorithm here is to read the nlist entries in m-sized
|
||||
// chunks into q. q is then iterated over. for each entry in q,
|
||||
// use the string table index(q->n_un.n_strx) to read the symbol
|
||||
// name, then scan the nlist entries passed in by the user(via p),
|
||||
// and look for a match
|
||||
while (n) { |
||||
long savpos; |
||||
|
||||
m = sizeof (space); |
||||
if (n < m) |
||||
m = n; |
||||
if (read(fd, (char *)space, m) != m) |
||||
break; |
||||
n -= m; |
||||
savpos = lseek(fd, 0, SEEK_CUR); |
||||
for (q = space; (m -= sizeof(breakpad_nlist)) >= 0; q++) { |
||||
char nambuf[BUFSIZ]; |
||||
|
||||
if (q->n_un.n_strx == 0 || q->n_type & N_STAB) |
||||
continue; |
||||
|
||||
// seek to the location in the binary where the symbol
|
||||
// name is stored & read it into memory
|
||||
lseek(fd, ss+q->n_un.n_strx, SEEK_SET); |
||||
read(fd, nambuf, maxlen+1); |
||||
s2 = nambuf; |
||||
for (p = list;
|
||||
symbolNames[p-list] &&
|
||||
symbolNames[p-list][0];
|
||||
p++) { |
||||
// get the symbol name the user has passed in that
|
||||
// corresponds to the nlist entry that we're looking at
|
||||
s1 = symbolNames[p - list]; |
||||
while (*s1) { |
||||
if (*s1++ != *s2++) |
||||
goto cont; |
||||
} |
||||
if (*s2) |
||||
goto cont; |
||||
|
||||
p->n_value = q->n_value; |
||||
p->n_type = q->n_type; |
||||
p->n_desc = q->n_desc; |
||||
p->n_sect = q->n_sect; |
||||
p->n_un.n_strx = q->n_un.n_strx; |
||||
if (--nreq == 0) |
||||
return (nreq); |
||||
|
||||
break; |
||||
cont: ; |
||||
} |
||||
} |
||||
lseek(fd, savpos, SEEK_SET); |
||||
} |
||||
return (nreq); |
||||
} |
||||
|
||||
#endif /* __LP64__ */ |
@ -0,0 +1,43 @@ |
||||
// Copyright (c) 2008, Google Inc.
|
||||
// All rights reserved
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// breakpad_nlist.h
|
||||
//
|
||||
// This file is meant to provide a header for clients of the modified
|
||||
// nlist function implemented to work on 64-bit.
|
||||
|
||||
#ifndef CLIENT_MAC_HANDLER_BREAKPAD_NLIST_H__ |
||||
|
||||
typedef struct nlist_64 breakpad_nlist; |
||||
|
||||
int |
||||
breakpad_nlist_64(const char *name, |
||||
breakpad_nlist *list, |
||||
const char **symbolNames); |
||||
|
||||
#endif /* CLIENT_MAC_HANDLER_BREAKPAD_NLIST_H__ */ |
@ -0,0 +1,456 @@ |
||||
// Copyright (c) 2007, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
extern "C" { // needed to compile on Leopard
|
||||
#include <mach-o/getsect.h> |
||||
#include <mach-o/nlist.h> |
||||
#include <stdlib.h> |
||||
#include <stdio.h> |
||||
} |
||||
|
||||
#include "breakpad_nlist_64.h" |
||||
#include <dlfcn.h> |
||||
#include <mach/mach_vm.h> |
||||
#include <algorithm> |
||||
#include "client/mac/handler/dynamic_images.h" |
||||
|
||||
namespace google_breakpad { |
||||
|
||||
//==============================================================================
|
||||
// Returns the size of the memory region containing |address| and the
|
||||
// number of bytes from |address| to the end of the region.
|
||||
// We potentially, will extend the size of the original
|
||||
// region by the size of the following region if it's contiguous with the
|
||||
// first in order to handle cases when we're reading strings and they
|
||||
// straddle two vm regions.
|
||||
//
|
||||
static mach_vm_size_t GetMemoryRegionSize(task_port_t target_task, |
||||
const void* address, |
||||
mach_vm_size_t *size_to_end) { |
||||
mach_vm_address_t region_base = (mach_vm_address_t)address; |
||||
mach_vm_size_t region_size; |
||||
natural_t nesting_level = 0; |
||||
vm_region_submap_info_64 submap_info; |
||||
mach_msg_type_number_t info_count = VM_REGION_SUBMAP_INFO_COUNT_64; |
||||
|
||||
// Get information about the vm region containing |address|
|
||||
vm_region_recurse_info_t region_info; |
||||
region_info = reinterpret_cast<vm_region_recurse_info_t>(&submap_info); |
||||
|
||||
kern_return_t result = |
||||
mach_vm_region_recurse(target_task, |
||||
®ion_base, |
||||
®ion_size, |
||||
&nesting_level, |
||||
region_info, |
||||
&info_count); |
||||
|
||||
if (result == KERN_SUCCESS) { |
||||
// Get distance from |address| to the end of this region
|
||||
*size_to_end = region_base + region_size -(mach_vm_address_t)address; |
||||
|
||||
// If we want to handle strings as long as 4096 characters we may need
|
||||
// to check if there's a vm region immediately following the first one.
|
||||
// If so, we need to extend |*size_to_end| to go all the way to the end
|
||||
// of the second region.
|
||||
if (*size_to_end < 4096) { |
||||
// Second region starts where the first one ends
|
||||
mach_vm_address_t region_base2 = |
||||
(mach_vm_address_t)(region_base + region_size); |
||||
mach_vm_size_t region_size2; |
||||
|
||||
// Get information about the following vm region
|
||||
result = |
||||
mach_vm_region_recurse(target_task, |
||||
®ion_base2, |
||||
®ion_size2, |
||||
&nesting_level, |
||||
region_info, |
||||
&info_count); |
||||
|
||||
// Extend region_size to go all the way to the end of the 2nd region
|
||||
if (result == KERN_SUCCESS |
||||
&& region_base2 == region_base + region_size) { |
||||
region_size += region_size2; |
||||
} |
||||
} |
||||
|
||||
*size_to_end = region_base + region_size -(mach_vm_address_t)address; |
||||
} else { |
||||
region_size = 0; |
||||
*size_to_end = 0; |
||||
} |
||||
|
||||
return region_size; |
||||
} |
||||
|
||||
#define kMaxStringLength 8192 |
||||
//==============================================================================
|
||||
// Reads a NULL-terminated string from another task.
|
||||
//
|
||||
// Warning! This will not read any strings longer than kMaxStringLength-1
|
||||
//
|
||||
static void* ReadTaskString(task_port_t target_task, |
||||
const void* address) { |
||||
// The problem is we don't know how much to read until we know how long
|
||||
// the string is. And we don't know how long the string is, until we've read
|
||||
// the memory! So, we'll try to read kMaxStringLength bytes
|
||||
// (or as many bytes as we can until we reach the end of the vm region).
|
||||
mach_vm_size_t size_to_end; |
||||
GetMemoryRegionSize(target_task, address, &size_to_end); |
||||
|
||||
if (size_to_end > 0) { |
||||
mach_vm_size_t size_to_read = |
||||
size_to_end > kMaxStringLength ? kMaxStringLength : size_to_end; |
||||
|
||||
kern_return_t kr; |
||||
return ReadTaskMemory(target_task, address, size_to_read, &kr); |
||||
} |
||||
|
||||
return NULL; |
||||
} |
||||
|
||||
//==============================================================================
|
||||
// Reads an address range from another task. A block of memory is malloced
|
||||
// and should be freed by the caller.
|
||||
void* ReadTaskMemory(task_port_t target_task, |
||||
const void* address, |
||||
size_t length, |
||||
kern_return_t *kr) { |
||||
void* result = NULL; |
||||
int systemPageSize = getpagesize(); |
||||
|
||||
// use the negative of the page size for the mask to find the page address
|
||||
mach_vm_address_t page_address = |
||||
reinterpret_cast<mach_vm_address_t>(address) & (-systemPageSize); |
||||
|
||||
mach_vm_address_t last_page_address = |
||||
(reinterpret_cast<mach_vm_address_t>(address) + length + |
||||
(systemPageSize - 1)) & (-systemPageSize); |
||||
|
||||
mach_vm_size_t page_size = last_page_address - page_address; |
||||
uint8_t* local_start; |
||||
uint32_t local_length; |
||||
|
||||
kern_return_t r; |
||||
|
||||
r = mach_vm_read(target_task, |
||||
page_address, |
||||
page_size, |
||||
reinterpret_cast<vm_offset_t*>(&local_start), |
||||
&local_length); |
||||
|
||||
|
||||
if (kr != NULL) { |
||||
*kr = r; |
||||
} |
||||
|
||||
if (r == KERN_SUCCESS) { |
||||
result = malloc(length); |
||||
if (result != NULL) { |
||||
memcpy(result, |
||||
&local_start[(mach_vm_address_t)address - page_address], |
||||
length); |
||||
} |
||||
mach_vm_deallocate(mach_task_self(), (uintptr_t)local_start, local_length); |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
#pragma mark - |
||||
|
||||
//==============================================================================
|
||||
// Initializes vmaddr_, vmsize_, and slide_
|
||||
void DynamicImage::CalculateMemoryAndVersionInfo() { |
||||
breakpad_mach_header *header = GetMachHeader(); |
||||
|
||||
// unless we can process the header, ensure that calls to
|
||||
// IsValid() will return false
|
||||
vmaddr_ = 0; |
||||
vmsize_ = 0; |
||||
slide_ = 0; |
||||
version_ = 0; |
||||
|
||||
bool foundTextSection = false; |
||||
bool foundDylibIDCommand = false; |
||||
|
||||
#if __LP64__ |
||||
if(header->magic != MH_MAGIC_64) { |
||||
return; |
||||
} |
||||
#else |
||||
if(header->magic != MH_MAGIC) { |
||||
return; |
||||
} |
||||
#endif |
||||
|
||||
uint32_t versionSize = 0; |
||||
#ifdef __LP64__ |
||||
const uint32_t segmentLoadCommand = LC_SEGMENT_64; |
||||
char* sectVersion = getsectdatafromheader_64(header, SEG_DATA, "__version", &versionSize); |
||||
#else |
||||
const uint32_t segmentLoadCommand = LC_SEGMENT; |
||||
char* sectVersion = getsectdatafromheader(header, SEG_DATA, "__version", &versionSize); |
||||
#endif |
||||
|
||||
if (versionSize == 4) { |
||||
version_ = NXSwapHostLongToBig(*(unsigned long*)sectVersion); |
||||
} |
||||
|
||||
const struct load_command *cmd = |
||||
reinterpret_cast<const struct load_command *>(header + 1); |
||||
|
||||
for (unsigned int i = 0; cmd && (i < header->ncmds); ++i) { |
||||
if (!foundTextSection) { |
||||
if (cmd->cmd == segmentLoadCommand) { |
||||
const breakpad_mach_segment_command *seg = |
||||
reinterpret_cast<const breakpad_mach_segment_command *>(cmd); |
||||
|
||||
if (!strcmp(seg->segname, "__TEXT")) { |
||||
vmaddr_ = seg->vmaddr; |
||||
vmsize_ = seg->vmsize; |
||||
slide_ = 0; |
||||
|
||||
if (seg->fileoff == 0 && seg->filesize != 0) { |
||||
slide_ = (uintptr_t)GetLoadAddress() - (uintptr_t)seg->vmaddr; |
||||
} |
||||
foundTextSection = true; |
||||
} |
||||
} |
||||
} |
||||
|
||||
if (!foundDylibIDCommand) { |
||||
if (cmd->cmd == LC_ID_DYLIB) { |
||||
const struct dylib_command *dc = |
||||
reinterpret_cast<const struct dylib_command *>(cmd); |
||||
|
||||
version_ = dc->dylib.current_version; |
||||
foundDylibIDCommand = true; |
||||
} |
||||
} |
||||
|
||||
if (foundDylibIDCommand && foundTextSection) { |
||||
return; |
||||
} |
||||
|
||||
cmd = reinterpret_cast<const struct load_command *> |
||||
(reinterpret_cast<const char *>(cmd) + cmd->cmdsize); |
||||
} |
||||
|
||||
} |
||||
|
||||
void DynamicImage::Print() { |
||||
const char *path = GetFilePath(); |
||||
if (!path) { |
||||
path = "(unknown)"; |
||||
} |
||||
printf("%p: %s\n", GetLoadAddress(), path); |
||||
breakpad_mach_header *header = GetMachHeader(); |
||||
MachHeader(*header).Print(); |
||||
printf("vmaddr\t\t: %p\n", reinterpret_cast<void*>(GetVMAddr())); |
||||
printf("vmsize\t\t: %llu\n", GetVMSize()); |
||||
printf("slide\t\t: %td\n", GetVMAddrSlide()); |
||||
} |
||||
|
||||
#pragma mark - |
||||
|
||||
//==============================================================================
|
||||
// Loads information about dynamically loaded code in the given task.
|
||||
DynamicImages::DynamicImages(mach_port_t task) |
||||
: task_(task) { |
||||
ReadImageInfoForTask(); |
||||
} |
||||
|
||||
void* DynamicImages::GetDyldAllImageInfosPointer() |
||||
{ |
||||
|
||||
const char *imageSymbolName = "_dyld_all_image_infos"; |
||||
const char *dyldPath = "/usr/lib/dyld"; |
||||
#ifndef __LP64__ |
||||
struct nlist l[8]; |
||||
memset(l, 0, sizeof(l) ); |
||||
|
||||
// First we lookup the address of the "_dyld_all_image_infos" struct
|
||||
// which lives in "dyld". This structure contains information about all
|
||||
// of the loaded dynamic images.
|
||||
struct nlist &list = l[0]; |
||||
list.n_un.n_name = const_cast<char *>(imageSymbolName); |
||||
nlist(dyldPath,&list); |
||||
if(list.n_value) { |
||||
return reinterpret_cast<void*>(list.n_value); |
||||
} |
||||
|
||||
return NULL; |
||||
#else |
||||
struct nlist_64 l[8]; |
||||
struct nlist_64 &list = l[0]; |
||||
|
||||
memset(l, 0, sizeof(l) ); |
||||
|
||||
const char *symbolNames[2] = { imageSymbolName, "\0" }; |
||||
|
||||
int invalidEntriesCount = breakpad_nlist_64(dyldPath,&list,symbolNames); |
||||
|
||||
if(invalidEntriesCount != 0) { |
||||
return NULL; |
||||
} |
||||
assert(list.n_value); |
||||
return reinterpret_cast<void*>(list.n_value); |
||||
#endif |
||||
|
||||
} |
||||
//==============================================================================
|
||||
// This code was written using dyld_debug.c (from Darwin) as a guide.
|
||||
void DynamicImages::ReadImageInfoForTask() { |
||||
void *imageList = GetDyldAllImageInfosPointer(); |
||||
|
||||
if (imageList) { |
||||
kern_return_t kr; |
||||
// Read the structure inside of dyld that contains information about
|
||||
// loaded images. We're reading from the desired task's address space.
|
||||
|
||||
// Here we make the assumption that dyld loaded at the same address in
|
||||
// the crashed process vs. this one. This is an assumption made in
|
||||
// "dyld_debug.c" and is said to be nearly always valid.
|
||||
dyld_all_image_infos *dyldInfo = reinterpret_cast<dyld_all_image_infos*> |
||||
(ReadTaskMemory(task_, |
||||
reinterpret_cast<void*>(imageList), |
||||
sizeof(dyld_all_image_infos), &kr)); |
||||
|
||||
if (dyldInfo) { |
||||
// number of loaded images
|
||||
int count = dyldInfo->infoArrayCount; |
||||
|
||||
// Read an array of dyld_image_info structures each containing
|
||||
// information about a loaded image.
|
||||
dyld_image_info *infoArray = reinterpret_cast<dyld_image_info*> |
||||
(ReadTaskMemory(task_, |
||||
dyldInfo->infoArray, |
||||
count*sizeof(dyld_image_info), &kr)); |
||||
|
||||
image_list_.reserve(count); |
||||
|
||||
for (int i = 0; i < count; ++i) { |
||||
dyld_image_info &info = infoArray[i]; |
||||
|
||||
// First read just the mach_header from the image in the task.
|
||||
breakpad_mach_header *header = reinterpret_cast<breakpad_mach_header*> |
||||
(ReadTaskMemory(task_, |
||||
info.load_address_, |
||||
sizeof(breakpad_mach_header), &kr)); |
||||
|
||||
if (!header) |
||||
break; // bail on this dynamic image
|
||||
|
||||
// Now determine the total amount we really want to read based on the
|
||||
// size of the load commands. We need the header plus all of the
|
||||
// load commands.
|
||||
unsigned int header_size = |
||||
sizeof(breakpad_mach_header) + header->sizeofcmds; |
||||
|
||||
free(header); |
||||
|
||||
header = reinterpret_cast<breakpad_mach_header*> |
||||
(ReadTaskMemory(task_, info.load_address_, header_size, &kr)); |
||||
|
||||
// Read the file name from the task's memory space.
|
||||
char *file_path = NULL; |
||||
if (info.file_path_) { |
||||
// Although we're reading kMaxStringLength bytes, it's copied in the
|
||||
// the DynamicImage constructor below with the correct string length,
|
||||
// so it's not really wasting memory.
|
||||
file_path = reinterpret_cast<char*> |
||||
(ReadTaskString(task_, info.file_path_)); |
||||
} |
||||
|
||||
// Create an object representing this image and add it to our list.
|
||||
DynamicImage *new_image; |
||||
new_image = new DynamicImage(header, |
||||
header_size, |
||||
(breakpad_mach_header*)info.load_address_, |
||||
file_path, |
||||
info.file_mod_date_, |
||||
task_); |
||||
|
||||
if (new_image->IsValid()) { |
||||
image_list_.push_back(DynamicImageRef(new_image)); |
||||
} else { |
||||
delete new_image; |
||||
} |
||||
|
||||
if (file_path) { |
||||
free(file_path); |
||||
} |
||||
} |
||||
|
||||
free(dyldInfo); |
||||
free(infoArray); |
||||
|
||||
// sorts based on loading address
|
||||
sort(image_list_.begin(), image_list_.end() ); |
||||
// remove duplicates - this happens in certain strange cases
|
||||
// You can see it in DashboardClient when Google Gadgets plugin
|
||||
// is installed. Apple's crash reporter log and gdb "info shared"
|
||||
// both show the same library multiple times at the same address
|
||||
|
||||
vector<DynamicImageRef>::iterator it = unique(image_list_.begin(), |
||||
image_list_.end() ); |
||||
image_list_.erase(it, image_list_.end()); |
||||
} |
||||
} |
||||
} |
||||
|
||||
//==============================================================================
|
||||
DynamicImage *DynamicImages::GetExecutableImage() { |
||||
int executable_index = GetExecutableImageIndex(); |
||||
|
||||
if (executable_index >= 0) { |
||||
return GetImage(executable_index); |
||||
} |
||||
|
||||
return NULL; |
||||
} |
||||
|
||||
//==============================================================================
|
||||
// returns -1 if failure to find executable
|
||||
int DynamicImages::GetExecutableImageIndex() { |
||||
int image_count = GetImageCount(); |
||||
|
||||
for (int i = 0; i < image_count; ++i) { |
||||
DynamicImage *image = GetImage(i); |
||||
if (image->GetMachHeader()->filetype == MH_EXECUTE) { |
||||
return i; |
||||
} |
||||
} |
||||
|
||||
return -1; |
||||
} |
||||
|
||||
} // namespace google_breakpad
|
@ -0,0 +1,297 @@ |
||||
// Copyright (c) 2007, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// dynamic_images.h
|
||||
//
|
||||
// Implements most of the function of the dyld API, but allowing an
|
||||
// arbitrary task to be introspected, unlike the dyld API which
|
||||
// only allows operation on the current task. The current implementation
|
||||
// is limited to use by 32-bit tasks.
|
||||
|
||||
#ifndef CLIENT_MAC_HANDLER_DYNAMIC_IMAGES_H__ |
||||
#define CLIENT_MAC_HANDLER_DYNAMIC_IMAGES_H__ |
||||
|
||||
#include <mach/mach.h> |
||||
#include <mach-o/dyld.h> |
||||
#include <mach-o/loader.h> |
||||
#include <sys/types.h> |
||||
#include <vector> |
||||
|
||||
namespace google_breakpad { |
||||
|
||||
using std::vector; |
||||
|
||||
//==============================================================================
|
||||
// The memory layout of this struct matches the dyld_image_info struct
|
||||
// defined in "dyld_gdb.h" in the darwin source.
|
||||
typedef struct dyld_image_info { |
||||
struct mach_header *load_address_; |
||||
char *file_path_; |
||||
uintptr_t file_mod_date_; |
||||
} dyld_image_info; |
||||
|
||||
//==============================================================================
|
||||
// This is as defined in "dyld_gdb.h" in the darwin source.
|
||||
// _dyld_all_image_infos (in dyld) is a structure of this type
|
||||
// which will be used to determine which dynamic code has been loaded.
|
||||
typedef struct dyld_all_image_infos { |
||||
uint32_t version; // == 1 in Mac OS X 10.4
|
||||
uint32_t infoArrayCount; |
||||
const struct dyld_image_info *infoArray; |
||||
void* notification; |
||||
bool processDetachedFromSharedRegion; |
||||
} dyld_all_image_infos; |
||||
|
||||
// some typedefs to isolate 64/32 bit differences
|
||||
#ifdef __LP64__ |
||||
typedef mach_header_64 breakpad_mach_header; |
||||
typedef segment_command_64 breakpad_mach_segment_command; |
||||
#else |
||||
typedef mach_header breakpad_mach_header; |
||||
typedef segment_command breakpad_mach_segment_command; |
||||
#endif |
||||
|
||||
//==============================================================================
|
||||
// A simple wrapper for a mach_header
|
||||
//
|
||||
// This could be fleshed out with some more interesting methods.
|
||||
class MachHeader { |
||||
public: |
||||
explicit MachHeader(const breakpad_mach_header &header) : header_(header) {} |
||||
|
||||
void Print() { |
||||
printf("magic\t\t: %4x\n", header_.magic); |
||||
printf("cputype\t\t: %d\n", header_.cputype); |
||||
printf("cpusubtype\t: %d\n", header_.cpusubtype); |
||||
printf("filetype\t: %d\n", header_.filetype); |
||||
printf("ncmds\t\t: %d\n", header_.ncmds); |
||||
printf("sizeofcmds\t: %d\n", header_.sizeofcmds); |
||||
printf("flags\t\t: %d\n", header_.flags); |
||||
} |
||||
|
||||
breakpad_mach_header header_; |
||||
}; |
||||
|
||||
//==============================================================================
|
||||
// Represents a single dynamically loaded mach-o image
|
||||
class DynamicImage { |
||||
public: |
||||
DynamicImage(breakpad_mach_header *header, // we take ownership
|
||||
int header_size, // includes load commands
|
||||
breakpad_mach_header *load_address, |
||||
char *inFilePath, |
||||
uintptr_t image_mod_date, |
||||
mach_port_t task) |
||||
: header_(header), |
||||
header_size_(header_size), |
||||
load_address_(load_address), |
||||
file_mod_date_(image_mod_date), |
||||
task_(task) { |
||||
InitializeFilePath(inFilePath); |
||||
CalculateMemoryAndVersionInfo(); |
||||
} |
||||
|
||||
~DynamicImage() { |
||||
if (file_path_) { |
||||
free(file_path_); |
||||
} |
||||
free(header_); |
||||
} |
||||
|
||||
// Returns pointer to a local copy of the mach_header plus load commands
|
||||
breakpad_mach_header *GetMachHeader() {return header_;} |
||||
|
||||
// Size of mach_header plus load commands
|
||||
int GetHeaderSize() const {return header_size_;} |
||||
|
||||
// Full path to mach-o binary
|
||||
char *GetFilePath() {return file_path_;} |
||||
|
||||
uintptr_t GetModDate() const {return file_mod_date_;} |
||||
|
||||
// Actual address where the image was loaded
|
||||
breakpad_mach_header *GetLoadAddress() const {return load_address_;} |
||||
|
||||
// Address where the image should be loaded
|
||||
mach_vm_address_t GetVMAddr() const {return vmaddr_;} |
||||
|
||||
// Difference between GetLoadAddress() and GetVMAddr()
|
||||
ptrdiff_t GetVMAddrSlide() const {return slide_;} |
||||
|
||||
// Size of the image
|
||||
mach_vm_size_t GetVMSize() const {return vmsize_;} |
||||
|
||||
// Task owning this loaded image
|
||||
mach_port_t GetTask() {return task_;} |
||||
|
||||
uint32_t GetVersion() {return version_;} |
||||
// For sorting
|
||||
bool operator<(const DynamicImage &inInfo) { |
||||
return GetLoadAddress() < inInfo.GetLoadAddress(); |
||||
} |
||||
|
||||
// Debugging
|
||||
void Print(); |
||||
|
||||
private: |
||||
friend class DynamicImages; |
||||
|
||||
// Sanity checking
|
||||
bool IsValid() {return GetVMSize() != 0;} |
||||
|
||||
// Makes local copy of file path to mach-o binary
|
||||
void InitializeFilePath(char *inFilePath) { |
||||
if (inFilePath) { |
||||
size_t path_size = 1 + strlen(inFilePath); |
||||
file_path_ = reinterpret_cast<char*>(malloc(path_size)); |
||||
strlcpy(file_path_, inFilePath, path_size); |
||||
} else { |
||||
file_path_ = NULL; |
||||
} |
||||
} |
||||
|
||||
// Initializes vmaddr_, vmsize_, and slide_
|
||||
void CalculateMemoryAndVersionInfo(); |
||||
|
||||
breakpad_mach_header *header_; // our local copy of the header
|
||||
int header_size_; // mach_header plus load commands
|
||||
breakpad_mach_header *load_address_; // base address image is mapped into
|
||||
mach_vm_address_t vmaddr_; |
||||
mach_vm_size_t vmsize_; |
||||
ptrdiff_t slide_; |
||||
uint32_t version_; // Dylib version
|
||||
char *file_path_; // path dyld used to load the image
|
||||
uintptr_t file_mod_date_; // time_t of image file
|
||||
|
||||
mach_port_t task_; |
||||
}; |
||||
|
||||
//==============================================================================
|
||||
// DynamicImageRef is just a simple wrapper for a pointer to
|
||||
// DynamicImage. The reason we use it instead of a simple typedef is so
|
||||
// that we can use stl::sort() on a vector of DynamicImageRefs
|
||||
// and simple class pointers can't implement operator<().
|
||||
//
|
||||
class DynamicImageRef { |
||||
public: |
||||
explicit DynamicImageRef(DynamicImage *inP) : p(inP) {} |
||||
// The copy constructor is required by STL
|
||||
DynamicImageRef(const DynamicImageRef &inRef) : p(inRef.p) {} |
||||
|
||||
bool operator<(const DynamicImageRef &inRef) const { |
||||
return (*const_cast<DynamicImageRef*>(this)->p) |
||||
< (*const_cast<DynamicImageRef&>(inRef).p); |
||||
} |
||||
|
||||
bool operator==(const DynamicImageRef &inInfo) const { |
||||
return (*const_cast<DynamicImageRef*>(this)->p).GetLoadAddress() == |
||||
(*const_cast<DynamicImageRef&>(inInfo)).GetLoadAddress(); |
||||
} |
||||
|
||||
// Be just like DynamicImage*
|
||||
DynamicImage *operator->() {return p;} |
||||
operator DynamicImage*() {return p;} |
||||
|
||||
private: |
||||
DynamicImage *p; |
||||
}; |
||||
|
||||
//==============================================================================
|
||||
// An object of type DynamicImages may be created to allow introspection of
|
||||
// an arbitrary task's dynamically loaded mach-o binaries. This makes the
|
||||
// assumption that the current task has send rights to the target task.
|
||||
class DynamicImages { |
||||
public: |
||||
explicit DynamicImages(mach_port_t task); |
||||
|
||||
~DynamicImages() { |
||||
for (int i = 0; i < (int)image_list_.size(); ++i) { |
||||
delete image_list_[i]; |
||||
} |
||||
} |
||||
|
||||
// Returns the number of dynamically loaded mach-o images.
|
||||
int GetImageCount() const {return image_list_.size();} |
||||
|
||||
// Returns an individual image.
|
||||
DynamicImage *GetImage(int i) { |
||||
if (i < (int)image_list_.size()) { |
||||
return image_list_[i]; |
||||
} |
||||
return NULL; |
||||
} |
||||
|
||||
// Returns the image corresponding to the main executable.
|
||||
DynamicImage *GetExecutableImage(); |
||||
int GetExecutableImageIndex(); |
||||
|
||||
// Returns the task which we're looking at.
|
||||
mach_port_t GetTask() const {return task_;} |
||||
|
||||
// Debugging
|
||||
void Print() { |
||||
for (int i = 0; i < (int)image_list_.size(); ++i) { |
||||
image_list_[i]->Print(); |
||||
} |
||||
} |
||||
|
||||
void TestPrint() { |
||||
const breakpad_mach_header *header; |
||||
for (int i = 0; i < (int)image_list_.size(); ++i) { |
||||
printf("dyld: %p: name = %s\n", _dyld_get_image_header(i), |
||||
_dyld_get_image_name(i) ); |
||||
|
||||
const void *imageHeader = _dyld_get_image_header(i); |
||||
header = reinterpret_cast<const breakpad_mach_header*>(imageHeader); |
||||
|
||||
MachHeader(*header).Print(); |
||||
} |
||||
} |
||||
|
||||
private: |
||||
bool IsOurTask() {return task_ == mach_task_self();} |
||||
|
||||
// Initialization
|
||||
void ReadImageInfoForTask(); |
||||
void* GetDyldAllImageInfosPointer(); |
||||
|
||||
mach_port_t task_; |
||||
vector<DynamicImageRef> image_list_; |
||||
}; |
||||
|
||||
// Returns a malloced block containing the contents of memory at a particular
|
||||
// location in another task.
|
||||
void* ReadTaskMemory(task_port_t target_task, |
||||
const void* address, |
||||
size_t len, |
||||
kern_return_t *kr); |
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // CLIENT_MAC_HANDLER_DYNAMIC_IMAGES_H__
|
@ -0,0 +1,722 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <map> |
||||
#include <pthread.h> |
||||
|
||||
#include "client/mac/handler/exception_handler.h" |
||||
#include "client/mac/handler/minidump_generator.h" |
||||
#include "common/mac/macho_utilities.h" |
||||
|
||||
#ifndef USE_PROTECTED_ALLOCATIONS |
||||
#define USE_PROTECTED_ALLOCATIONS 0 |
||||
#endif |
||||
|
||||
// If USE_PROTECTED_ALLOCATIONS is activated then the
|
||||
// gBreakpadAllocator needs to be setup in other code
|
||||
// ahead of time. Please see ProtectedMemoryAllocator.h
|
||||
// for more details.
|
||||
#if USE_PROTECTED_ALLOCATIONS |
||||
#include "protected_memory_allocator.h" |
||||
extern ProtectedMemoryAllocator *gBreakpadAllocator; |
||||
#endif |
||||
|
||||
|
||||
namespace google_breakpad { |
||||
|
||||
using std::map; |
||||
|
||||
// These structures and techniques are illustrated in
|
||||
// Mac OS X Internals, Amit Singh, ch 9.7
|
||||
struct ExceptionMessage { |
||||
mach_msg_header_t header; |
||||
mach_msg_body_t body; |
||||
mach_msg_port_descriptor_t thread; |
||||
mach_msg_port_descriptor_t task; |
||||
NDR_record_t ndr; |
||||
exception_type_t exception; |
||||
mach_msg_type_number_t code_count; |
||||
integer_t code[EXCEPTION_CODE_MAX]; |
||||
char padding[512]; |
||||
}; |
||||
|
||||
struct ExceptionParameters { |
||||
ExceptionParameters() : count(0) {} |
||||
mach_msg_type_number_t count; |
||||
exception_mask_t masks[EXC_TYPES_COUNT]; |
||||
mach_port_t ports[EXC_TYPES_COUNT]; |
||||
exception_behavior_t behaviors[EXC_TYPES_COUNT]; |
||||
thread_state_flavor_t flavors[EXC_TYPES_COUNT]; |
||||
}; |
||||
|
||||
struct ExceptionReplyMessage { |
||||
mach_msg_header_t header; |
||||
NDR_record_t ndr; |
||||
kern_return_t return_code; |
||||
}; |
||||
|
||||
// Only catch these three exceptions. The other ones are nebulously defined
|
||||
// and may result in treating a non-fatal exception as fatal.
|
||||
exception_mask_t s_exception_mask = EXC_MASK_BAD_ACCESS | |
||||
EXC_MASK_BAD_INSTRUCTION | EXC_MASK_ARITHMETIC | EXC_MASK_BREAKPOINT; |
||||
|
||||
extern "C" |
||||
{ |
||||
// Forward declarations for functions that need "C" style compilation
|
||||
boolean_t exc_server(mach_msg_header_t *request, |
||||
mach_msg_header_t *reply); |
||||
|
||||
kern_return_t catch_exception_raise(mach_port_t target_port, |
||||
mach_port_t failed_thread, |
||||
mach_port_t task, |
||||
exception_type_t exception, |
||||
exception_data_t code, |
||||
mach_msg_type_number_t code_count); |
||||
|
||||
kern_return_t ForwardException(mach_port_t task, |
||||
mach_port_t failed_thread, |
||||
exception_type_t exception, |
||||
exception_data_t code, |
||||
mach_msg_type_number_t code_count); |
||||
|
||||
kern_return_t exception_raise(mach_port_t target_port, |
||||
mach_port_t failed_thread, |
||||
mach_port_t task, |
||||
exception_type_t exception, |
||||
exception_data_t exception_code, |
||||
mach_msg_type_number_t exception_code_count); |
||||
|
||||
kern_return_t |
||||
exception_raise_state(mach_port_t target_port, |
||||
mach_port_t failed_thread, |
||||
mach_port_t task, |
||||
exception_type_t exception, |
||||
exception_data_t exception_code, |
||||
mach_msg_type_number_t code_count, |
||||
thread_state_flavor_t *target_flavor, |
||||
thread_state_t thread_state, |
||||
mach_msg_type_number_t thread_state_count, |
||||
thread_state_t thread_state, |
||||
mach_msg_type_number_t *thread_state_count); |
||||
|
||||
kern_return_t |
||||
exception_raise_state_identity(mach_port_t target_port, |
||||
mach_port_t failed_thread, |
||||
mach_port_t task, |
||||
exception_type_t exception, |
||||
exception_data_t exception_code, |
||||
mach_msg_type_number_t exception_code_count, |
||||
thread_state_flavor_t *target_flavor, |
||||
thread_state_t thread_state, |
||||
mach_msg_type_number_t thread_state_count, |
||||
thread_state_t thread_state, |
||||
mach_msg_type_number_t *thread_state_count); |
||||
|
||||
kern_return_t breakpad_exception_raise_state(mach_port_t exception_port, |
||||
exception_type_t exception, |
||||
const exception_data_t code, |
||||
mach_msg_type_number_t codeCnt, |
||||
int *flavor, |
||||
const thread_state_t old_state, |
||||
mach_msg_type_number_t old_stateCnt, |
||||
thread_state_t new_state, |
||||
mach_msg_type_number_t *new_stateCnt |
||||
); |
||||
|
||||
kern_return_t breakpad_exception_raise_state_identity(mach_port_t exception_port, |
||||
mach_port_t thread, |
||||
mach_port_t task, |
||||
exception_type_t exception, |
||||
exception_data_t code, |
||||
mach_msg_type_number_t codeCnt, |
||||
int *flavor, |
||||
thread_state_t old_state, |
||||
mach_msg_type_number_t old_stateCnt, |
||||
thread_state_t new_state, |
||||
mach_msg_type_number_t *new_stateCnt |
||||
); |
||||
|
||||
kern_return_t breakpad_exception_raise(mach_port_t port, mach_port_t failed_thread, |
||||
mach_port_t task, |
||||
exception_type_t exception, |
||||
exception_data_t code, |
||||
mach_msg_type_number_t code_count); |
||||
} |
||||
|
||||
|
||||
|
||||
kern_return_t breakpad_exception_raise_state(mach_port_t exception_port, |
||||
exception_type_t exception, |
||||
const exception_data_t code, |
||||
mach_msg_type_number_t codeCnt, |
||||
int *flavor, |
||||
const thread_state_t old_state, |
||||
mach_msg_type_number_t old_stateCnt, |
||||
thread_state_t new_state, |
||||
mach_msg_type_number_t *new_stateCnt |
||||
) |
||||
{ |
||||
return KERN_SUCCESS; |
||||
} |
||||
|
||||
kern_return_t breakpad_exception_raise_state_identity(mach_port_t exception_port, |
||||
mach_port_t thread, |
||||
mach_port_t task, |
||||
exception_type_t exception, |
||||
exception_data_t code, |
||||
mach_msg_type_number_t codeCnt, |
||||
int *flavor, |
||||
thread_state_t old_state, |
||||
mach_msg_type_number_t old_stateCnt, |
||||
thread_state_t new_state, |
||||
mach_msg_type_number_t *new_stateCnt |
||||
) |
||||
{ |
||||
return KERN_SUCCESS; |
||||
} |
||||
|
||||
kern_return_t breakpad_exception_raise(mach_port_t port, mach_port_t failed_thread, |
||||
mach_port_t task, |
||||
exception_type_t exception, |
||||
exception_data_t code, |
||||
mach_msg_type_number_t code_count) { |
||||
|
||||
if (task != mach_task_self()) { |
||||
return KERN_FAILURE; |
||||
} |
||||
return ForwardException(task, failed_thread, exception, code, code_count); |
||||
} |
||||
|
||||
|
||||
ExceptionHandler::ExceptionHandler(const string &dump_path, |
||||
FilterCallback filter, |
||||
MinidumpCallback callback, |
||||
void *callback_context, |
||||
bool install_handler) |
||||
: dump_path_(), |
||||
filter_(filter), |
||||
callback_(callback), |
||||
callback_context_(callback_context), |
||||
directCallback_(NULL), |
||||
handler_thread_(NULL), |
||||
handler_port_(MACH_PORT_NULL), |
||||
previous_(NULL), |
||||
installed_exception_handler_(false), |
||||
is_in_teardown_(false), |
||||
last_minidump_write_result_(false), |
||||
use_minidump_write_mutex_(false) { |
||||
// This will update to the ID and C-string pointers
|
||||
set_dump_path(dump_path); |
||||
MinidumpGenerator::GatherSystemInformation(); |
||||
Setup(install_handler); |
||||
} |
||||
|
||||
// special constructor if we want to bypass minidump writing and
|
||||
// simply get a callback with the exception information
|
||||
ExceptionHandler::ExceptionHandler(DirectCallback callback, |
||||
void *callback_context, |
||||
bool install_handler) |
||||
: dump_path_(), |
||||
filter_(NULL), |
||||
callback_(NULL), |
||||
callback_context_(callback_context), |
||||
directCallback_(callback), |
||||
handler_thread_(NULL), |
||||
handler_port_(MACH_PORT_NULL), |
||||
previous_(NULL), |
||||
installed_exception_handler_(false), |
||||
is_in_teardown_(false), |
||||
last_minidump_write_result_(false), |
||||
use_minidump_write_mutex_(false) { |
||||
MinidumpGenerator::GatherSystemInformation(); |
||||
Setup(install_handler); |
||||
} |
||||
|
||||
ExceptionHandler::~ExceptionHandler() { |
||||
Teardown(); |
||||
} |
||||
|
||||
bool ExceptionHandler::WriteMinidump() { |
||||
// If we're currently writing, just return
|
||||
if (use_minidump_write_mutex_) |
||||
return false; |
||||
|
||||
use_minidump_write_mutex_ = true; |
||||
last_minidump_write_result_ = false; |
||||
|
||||
// Lock the mutex. Since we just created it, this will return immediately.
|
||||
if (pthread_mutex_lock(&minidump_write_mutex_) == 0) { |
||||
// Send an empty message to the handle port so that a minidump will
|
||||
// be written
|
||||
SendEmptyMachMessage(); |
||||
|
||||
// Wait for the minidump writer to complete its writing. It will unlock
|
||||
// the mutex when completed
|
||||
pthread_mutex_lock(&minidump_write_mutex_); |
||||
} |
||||
|
||||
use_minidump_write_mutex_ = false; |
||||
UpdateNextID(); |
||||
return last_minidump_write_result_; |
||||
} |
||||
|
||||
// static
|
||||
bool ExceptionHandler::WriteMinidump(const string &dump_path, |
||||
MinidumpCallback callback, |
||||
void *callback_context) { |
||||
ExceptionHandler handler(dump_path, NULL, callback, callback_context, false); |
||||
return handler.WriteMinidump(); |
||||
} |
||||
|
||||
bool ExceptionHandler::WriteMinidumpWithException(int exception_type, |
||||
int exception_code, |
||||
mach_port_t thread_name) { |
||||
bool result = false; |
||||
|
||||
if (directCallback_) { |
||||
if (directCallback_(callback_context_, |
||||
exception_type, |
||||
exception_code, |
||||
thread_name) ) { |
||||
if (exception_type && exception_code) |
||||
_exit(exception_type); |
||||
} |
||||
} else { |
||||
string minidump_id; |
||||
|
||||
// Putting the MinidumpGenerator in its own context will ensure that the
|
||||
// destructor is executed, closing the newly created minidump file.
|
||||
if (!dump_path_.empty()) { |
||||
MinidumpGenerator md; |
||||
if (exception_type && exception_code) { |
||||
// If this is a real exception, give the filter (if any) a chance to
|
||||
// decided if this should be sent
|
||||
if (filter_ && !filter_(callback_context_)) |
||||
return false; |
||||
|
||||
md.SetExceptionInformation(exception_type, exception_code, thread_name); |
||||
} |
||||
|
||||
result = md.Write(next_minidump_path_c_); |
||||
} |
||||
|
||||
// Call user specified callback (if any)
|
||||
if (callback_) { |
||||
// If the user callback returned true and we're handling an exception
|
||||
// (rather than just writing out the file), then we should exit without
|
||||
// forwarding the exception to the next handler.
|
||||
if (callback_(dump_path_c_, next_minidump_id_c_, callback_context_, |
||||
result)) { |
||||
if (exception_type && exception_code) |
||||
_exit(exception_type); |
||||
} |
||||
} |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
kern_return_t ForwardException(mach_port_t task, mach_port_t failed_thread, |
||||
exception_type_t exception, |
||||
exception_data_t code, |
||||
mach_msg_type_number_t code_count) { |
||||
// At this time, we should have called Uninstall() on the exception handler
|
||||
// so that the current exception ports are the ones that we should be
|
||||
// forwarding to.
|
||||
ExceptionParameters current; |
||||
|
||||
current.count = EXC_TYPES_COUNT; |
||||
mach_port_t current_task = mach_task_self(); |
||||
kern_return_t result = task_get_exception_ports(current_task, |
||||
s_exception_mask, |
||||
current.masks, |
||||
¤t.count, |
||||
current.ports, |
||||
current.behaviors, |
||||
current.flavors); |
||||
|
||||
// Find the first exception handler that matches the exception
|
||||
unsigned int found; |
||||
for (found = 0; found < current.count; ++found) { |
||||
if (current.masks[found] & (1 << exception)) { |
||||
break; |
||||
} |
||||
} |
||||
|
||||
// Nothing to forward
|
||||
if (found == current.count) { |
||||
fprintf(stderr, "** No previous ports for forwarding!! \n"); |
||||
exit(KERN_FAILURE); |
||||
} |
||||
|
||||
mach_port_t target_port = current.ports[found]; |
||||
exception_behavior_t target_behavior = current.behaviors[found]; |
||||
thread_state_flavor_t target_flavor = current.flavors[found]; |
||||
|
||||
mach_msg_type_number_t thread_state_count = THREAD_STATE_MAX; |
||||
breakpad_thread_state_data_t thread_state; |
||||
switch (target_behavior) { |
||||
case EXCEPTION_DEFAULT: |
||||
result = exception_raise(target_port, failed_thread, task, exception, |
||||
code, code_count); |
||||
break; |
||||
|
||||
case EXCEPTION_STATE: |
||||
result = thread_get_state(failed_thread, target_flavor, thread_state, |
||||
&thread_state_count); |
||||
if (result == KERN_SUCCESS) |
||||
result = exception_raise_state(target_port, failed_thread, task, |
||||
exception, code, |
||||
code_count, &target_flavor, |
||||
thread_state, thread_state_count, |
||||
thread_state, &thread_state_count); |
||||
if (result == KERN_SUCCESS) |
||||
result = thread_set_state(failed_thread, target_flavor, thread_state, |
||||
thread_state_count); |
||||
break; |
||||
|
||||
case EXCEPTION_STATE_IDENTITY: |
||||
result = thread_get_state(failed_thread, target_flavor, thread_state, |
||||
&thread_state_count); |
||||
if (result == KERN_SUCCESS) |
||||
result = exception_raise_state_identity(target_port, failed_thread, |
||||
task, exception, code, |
||||
code_count, &target_flavor, |
||||
thread_state, |
||||
thread_state_count, |
||||
thread_state, |
||||
&thread_state_count); |
||||
if (result == KERN_SUCCESS) |
||||
result = thread_set_state(failed_thread, target_flavor, thread_state, |
||||
thread_state_count); |
||||
break; |
||||
|
||||
default: |
||||
fprintf(stderr, "** Unknown exception behavior\n"); |
||||
result = KERN_FAILURE; |
||||
break; |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
// Callback from exc_server()
|
||||
kern_return_t catch_exception_raise(mach_port_t port, mach_port_t failed_thread, |
||||
mach_port_t task, |
||||
exception_type_t exception, |
||||
exception_data_t code, |
||||
mach_msg_type_number_t code_count) { |
||||
return ForwardException(task, failed_thread, exception, code, code_count); |
||||
} |
||||
|
||||
// static
|
||||
void *ExceptionHandler::WaitForMessage(void *exception_handler_class) { |
||||
ExceptionHandler *self = |
||||
reinterpret_cast<ExceptionHandler *>(exception_handler_class); |
||||
ExceptionMessage receive; |
||||
|
||||
// Wait for the exception info
|
||||
while (1) { |
||||
receive.header.msgh_local_port = self->handler_port_; |
||||
receive.header.msgh_size = sizeof(receive); |
||||
kern_return_t result = mach_msg(&(receive.header), |
||||
MACH_RCV_MSG | MACH_RCV_LARGE, 0, |
||||
sizeof(receive), self->handler_port_, |
||||
MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); |
||||
|
||||
|
||||
if (result == KERN_SUCCESS) { |
||||
// Uninstall our handler so that we don't get in a loop if the process of
|
||||
// writing out a minidump causes an exception. However, if the exception
|
||||
// was caused by a fork'd process, don't uninstall things
|
||||
|
||||
// If the actual exception code is zero, then we're calling this handler
|
||||
// in a way that indicates that we want to either exit this thread or
|
||||
// generate a minidump
|
||||
//
|
||||
// While reporting, all threads (except this one) must be suspended
|
||||
// to avoid misleading stacks. If appropriate they will be resumed
|
||||
// afterwards.
|
||||
if (!receive.exception) { |
||||
if (self->is_in_teardown_) |
||||
return NULL; |
||||
|
||||
self->SuspendThreads(); |
||||
|
||||
#if USE_PROTECTED_ALLOCATIONS |
||||
if(gBreakpadAllocator) |
||||
gBreakpadAllocator->Unprotect(); |
||||
#endif |
||||
|
||||
// Write out the dump and save the result for later retrieval
|
||||
self->last_minidump_write_result_ = |
||||
self->WriteMinidumpWithException(0, 0, 0); |
||||
|
||||
self->UninstallHandler(false); |
||||
|
||||
#if USE_PROTECTED_ALLOCATIONS |
||||
if(gBreakpadAllocator) |
||||
gBreakpadAllocator->Protect(); |
||||
#endif |
||||
|
||||
self->ResumeThreads(); |
||||
|
||||
if (self->use_minidump_write_mutex_) |
||||
pthread_mutex_unlock(&self->minidump_write_mutex_); |
||||
} else { |
||||
|
||||
// When forking a child process with the exception handler installed,
|
||||
// if the child crashes, it will send the exception back to the parent
|
||||
// process. The check for task == self_task() ensures that only
|
||||
// exceptions that occur in the parent process are caught and
|
||||
// processed. If the exception was not caused by this task, we
|
||||
// still need to call into the exception server and have it return
|
||||
// KERN_FAILURE (see breakpad_exception_raise) in order for the kernel
|
||||
// to move onto the host exception handler for the child task
|
||||
if (receive.task.name == mach_task_self()) { |
||||
self->SuspendThreads(); |
||||
|
||||
#if USE_PROTECTED_ALLOCATIONS |
||||
if(gBreakpadAllocator) |
||||
gBreakpadAllocator->Unprotect(); |
||||
#endif |
||||
|
||||
// Generate the minidump with the exception data.
|
||||
self->WriteMinidumpWithException(receive.exception, receive.code[0], |
||||
receive.thread.name); |
||||
|
||||
self->UninstallHandler(true); |
||||
|
||||
#if USE_PROTECTED_ALLOCATIONS |
||||
if(gBreakpadAllocator) |
||||
gBreakpadAllocator->Protect(); |
||||
#endif |
||||
} |
||||
// Pass along the exception to the server, which will setup the
|
||||
// message and call breakpad_exception_raise() and put the return
|
||||
// code into the reply.
|
||||
ExceptionReplyMessage reply; |
||||
if (!exc_server(&receive.header, &reply.header)) |
||||
exit(1); |
||||
|
||||
// Send a reply and exit
|
||||
result = mach_msg(&(reply.header), MACH_SEND_MSG, |
||||
reply.header.msgh_size, 0, MACH_PORT_NULL, |
||||
MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); |
||||
} |
||||
} |
||||
} |
||||
|
||||
return NULL; |
||||
} |
||||
|
||||
bool ExceptionHandler::InstallHandler() { |
||||
try { |
||||
#if USE_PROTECTED_ALLOCATIONS |
||||
previous_ = new (gBreakpadAllocator->Allocate(sizeof(ExceptionParameters)) ) |
||||
ExceptionParameters(); |
||||
#else |
||||
previous_ = new ExceptionParameters(); |
||||
#endif |
||||
|
||||
} |
||||
catch (std::bad_alloc) { |
||||
return false; |
||||
} |
||||
|
||||
// Save the current exception ports so that we can forward to them
|
||||
previous_->count = EXC_TYPES_COUNT; |
||||
mach_port_t current_task = mach_task_self(); |
||||
kern_return_t result = task_get_exception_ports(current_task, |
||||
s_exception_mask, |
||||
previous_->masks, |
||||
&previous_->count, |
||||
previous_->ports, |
||||
previous_->behaviors, |
||||
previous_->flavors); |
||||
|
||||
// Setup the exception ports on this task
|
||||
if (result == KERN_SUCCESS) |
||||
result = task_set_exception_ports(current_task, s_exception_mask, |
||||
handler_port_, EXCEPTION_DEFAULT, |
||||
THREAD_STATE_NONE); |
||||
|
||||
installed_exception_handler_ = (result == KERN_SUCCESS); |
||||
|
||||
return installed_exception_handler_; |
||||
} |
||||
|
||||
bool ExceptionHandler::UninstallHandler(bool in_exception) { |
||||
kern_return_t result = KERN_SUCCESS; |
||||
|
||||
if (installed_exception_handler_) { |
||||
mach_port_t current_task = mach_task_self(); |
||||
|
||||
// Restore the previous ports
|
||||
for (unsigned int i = 0; i < previous_->count; ++i) { |
||||
result = task_set_exception_ports(current_task, previous_->masks[i], |
||||
previous_->ports[i], |
||||
previous_->behaviors[i], |
||||
previous_->flavors[i]); |
||||
if (result != KERN_SUCCESS) |
||||
return false; |
||||
} |
||||
|
||||
// this delete should NOT happen if an exception just occurred!
|
||||
if (!in_exception) { |
||||
#if USE_PROTECTED_ALLOCATIONS |
||||
previous_->~ExceptionParameters(); |
||||
#else |
||||
delete previous_; |
||||
#endif |
||||
} |
||||
|
||||
previous_ = NULL; |
||||
installed_exception_handler_ = false; |
||||
} |
||||
|
||||
return result == KERN_SUCCESS; |
||||
} |
||||
|
||||
bool ExceptionHandler::Setup(bool install_handler) { |
||||
if (pthread_mutex_init(&minidump_write_mutex_, NULL)) |
||||
return false; |
||||
|
||||
// Create a receive right
|
||||
mach_port_t current_task = mach_task_self(); |
||||
kern_return_t result = mach_port_allocate(current_task, |
||||
MACH_PORT_RIGHT_RECEIVE, |
||||
&handler_port_); |
||||
// Add send right
|
||||
if (result == KERN_SUCCESS) |
||||
result = mach_port_insert_right(current_task, handler_port_, handler_port_, |
||||
MACH_MSG_TYPE_MAKE_SEND); |
||||
|
||||
if (install_handler && result == KERN_SUCCESS) |
||||
if (!InstallHandler()) |
||||
return false; |
||||
|
||||
if (result == KERN_SUCCESS) { |
||||
// Install the handler in its own thread, detached as we won't be joining.
|
||||
pthread_attr_t attr; |
||||
pthread_attr_init(&attr); |
||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); |
||||
int thread_create_result = pthread_create(&handler_thread_, &attr, |
||||
&WaitForMessage, this); |
||||
pthread_attr_destroy(&attr); |
||||
result = thread_create_result ? KERN_FAILURE : KERN_SUCCESS; |
||||
} |
||||
|
||||
return result == KERN_SUCCESS ? true : false; |
||||
} |
||||
|
||||
bool ExceptionHandler::Teardown() { |
||||
kern_return_t result = KERN_SUCCESS; |
||||
is_in_teardown_ = true; |
||||
|
||||
if (!UninstallHandler(false)) |
||||
return false; |
||||
|
||||
// Send an empty message so that the handler_thread exits
|
||||
if (SendEmptyMachMessage()) { |
||||
mach_port_t current_task = mach_task_self(); |
||||
result = mach_port_deallocate(current_task, handler_port_); |
||||
if (result != KERN_SUCCESS) |
||||
return false; |
||||
} else { |
||||
return false; |
||||
} |
||||
|
||||
handler_thread_ = NULL; |
||||
handler_port_ = NULL; |
||||
pthread_mutex_destroy(&minidump_write_mutex_); |
||||
|
||||
return result == KERN_SUCCESS; |
||||
} |
||||
|
||||
bool ExceptionHandler::SendEmptyMachMessage() { |
||||
ExceptionMessage empty; |
||||
memset(&empty, 0, sizeof(empty)); |
||||
empty.header.msgh_size = sizeof(empty) - sizeof(empty.padding); |
||||
empty.header.msgh_remote_port = handler_port_; |
||||
empty.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, |
||||
MACH_MSG_TYPE_MAKE_SEND_ONCE); |
||||
kern_return_t result = mach_msg(&(empty.header), |
||||
MACH_SEND_MSG | MACH_SEND_TIMEOUT, |
||||
empty.header.msgh_size, 0, 0, |
||||
MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); |
||||
|
||||
return result == KERN_SUCCESS; |
||||
} |
||||
|
||||
void ExceptionHandler::UpdateNextID() { |
||||
next_minidump_path_ = |
||||
(MinidumpGenerator::UniqueNameInDirectory(dump_path_, &next_minidump_id_)); |
||||
|
||||
next_minidump_path_c_ = next_minidump_path_.c_str(); |
||||
next_minidump_id_c_ = next_minidump_id_.c_str(); |
||||
} |
||||
|
||||
bool ExceptionHandler::SuspendThreads() { |
||||
thread_act_port_array_t threads_for_task; |
||||
mach_msg_type_number_t thread_count; |
||||
|
||||
if (task_threads(mach_task_self(), &threads_for_task, &thread_count)) |
||||
return false; |
||||
|
||||
// suspend all of the threads except for this one
|
||||
for (unsigned int i = 0; i < thread_count; ++i) { |
||||
if (threads_for_task[i] != mach_thread_self()) { |
||||
if (thread_suspend(threads_for_task[i])) |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
bool ExceptionHandler::ResumeThreads() { |
||||
thread_act_port_array_t threads_for_task; |
||||
mach_msg_type_number_t thread_count; |
||||
|
||||
if (task_threads(mach_task_self(), &threads_for_task, &thread_count)) |
||||
return false; |
||||
|
||||
// resume all of the threads except for this one
|
||||
for (unsigned int i = 0; i < thread_count; ++i) { |
||||
if (threads_for_task[i] != mach_thread_self()) { |
||||
if (thread_resume(threads_for_task[i])) |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
} // namespace google_breakpad
|
@ -0,0 +1,212 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// exception_handler.h: MacOS exception handler
|
||||
// This class can install a Mach exception port handler to trap most common
|
||||
// programming errors. If an exception occurs, a minidump file will be
|
||||
// generated which contains detailed information about the process and the
|
||||
// exception.
|
||||
|
||||
#ifndef CLIENT_MAC_HANDLER_EXCEPTION_HANDLER_H__ |
||||
#define CLIENT_MAC_HANDLER_EXCEPTION_HANDLER_H__ |
||||
|
||||
#include <mach/mach.h> |
||||
|
||||
#include <string> |
||||
|
||||
namespace google_breakpad { |
||||
|
||||
using std::string; |
||||
|
||||
struct ExceptionParameters; |
||||
|
||||
class ExceptionHandler { |
||||
public: |
||||
// A callback function to run before Breakpad performs any substantial
|
||||
// processing of an exception. A FilterCallback is called before writing
|
||||
// a minidump. context is the parameter supplied by the user as
|
||||
// callback_context when the handler was created.
|
||||
//
|
||||
// If a FilterCallback returns true, Breakpad will continue processing,
|
||||
// attempting to write a minidump. If a FilterCallback returns false, Breakpad
|
||||
// will immediately report the exception as unhandled without writing a
|
||||
// minidump, allowing another handler the opportunity to handle it.
|
||||
typedef bool (*FilterCallback)(void *context); |
||||
|
||||
// A callback function to run after the minidump has been written.
|
||||
// |minidump_id| is a unique id for the dump, so the minidump
|
||||
// file is <dump_dir>/<minidump_id>.dmp.
|
||||
// |context| is the value passed into the constructor.
|
||||
// |succeeded| indicates whether a minidump file was successfully written.
|
||||
// Return true if the exception was fully handled and breakpad should exit.
|
||||
// Return false to allow any other exception handlers to process the
|
||||
// exception.
|
||||
typedef bool (*MinidumpCallback)(const char *dump_dir, |
||||
const char *minidump_id, |
||||
void *context, bool succeeded); |
||||
|
||||
// A callback function which will be called directly if an exception occurs.
|
||||
// This bypasses the minidump file writing and simply gives the client
|
||||
// the exception information.
|
||||
typedef bool (*DirectCallback)( void *context, |
||||
int exception_type, |
||||
int exception_code, |
||||
mach_port_t thread_name); |
||||
|
||||
// Creates a new ExceptionHandler instance to handle writing minidumps.
|
||||
// Minidump files will be written to dump_path, and the optional callback
|
||||
// is called after writing the dump file, as described above.
|
||||
// If install_handler is true, then a minidump will be written whenever
|
||||
// an unhandled exception occurs. If it is false, minidumps will only
|
||||
// be written when WriteMinidump is called.
|
||||
ExceptionHandler(const string &dump_path, |
||||
FilterCallback filter, MinidumpCallback callback, |
||||
void *callback_context, bool install_handler); |
||||
|
||||
// A special constructor if we want to bypass minidump writing and
|
||||
// simply get a callback with the exception information.
|
||||
ExceptionHandler(DirectCallback callback, |
||||
void *callback_context, |
||||
bool install_handler); |
||||
|
||||
~ExceptionHandler(); |
||||
|
||||
// Get and set the minidump path.
|
||||
string dump_path() const { return dump_path_; } |
||||
void set_dump_path(const string &dump_path) { |
||||
dump_path_ = dump_path; |
||||
dump_path_c_ = dump_path_.c_str(); |
||||
UpdateNextID(); // Necessary to put dump_path_ in next_minidump_path_.
|
||||
} |
||||
|
||||
// Writes a minidump immediately. This can be used to capture the
|
||||
// execution state independently of a crash. Returns true on success.
|
||||
bool WriteMinidump(); |
||||
|
||||
// Convenience form of WriteMinidump which does not require an
|
||||
// ExceptionHandler instance.
|
||||
static bool WriteMinidump(const string &dump_path, MinidumpCallback callback, |
||||
void *callback_context); |
||||
|
||||
private: |
||||
// Install the mach exception handler
|
||||
bool InstallHandler(); |
||||
|
||||
// Uninstall the mach exception handler (if any)
|
||||
bool UninstallHandler(bool in_exception); |
||||
|
||||
// Setup the handler thread, and if |install_handler| is true, install the
|
||||
// mach exception port handler
|
||||
bool Setup(bool install_handler); |
||||
|
||||
// Uninstall the mach exception handler (if any) and terminate the helper
|
||||
// thread
|
||||
bool Teardown(); |
||||
|
||||
// Send an "empty" mach message to the exception handler. Return true on
|
||||
// success, false otherwise
|
||||
bool SendEmptyMachMessage(); |
||||
|
||||
// All minidump writing goes through this one routine
|
||||
bool WriteMinidumpWithException(int exception_type, int exception_code, |
||||
mach_port_t thread_name); |
||||
|
||||
// When installed, this static function will be call from a newly created
|
||||
// pthread with |this| as the argument
|
||||
static void *WaitForMessage(void *exception_handler_class); |
||||
|
||||
// disallow copy ctor and operator=
|
||||
explicit ExceptionHandler(const ExceptionHandler &); |
||||
void operator=(const ExceptionHandler &); |
||||
|
||||
// Generates a new ID and stores it in next_minidump_id_, and stores the
|
||||
// path of the next minidump to be written in next_minidump_path_.
|
||||
void UpdateNextID(); |
||||
|
||||
// These functions will suspend/resume all threads except for the
|
||||
// reporting thread
|
||||
bool SuspendThreads(); |
||||
bool ResumeThreads(); |
||||
|
||||
// The destination directory for the minidump
|
||||
string dump_path_; |
||||
|
||||
// The basename of the next minidump w/o extension
|
||||
string next_minidump_id_; |
||||
|
||||
// The full path to the next minidump to be written, including extension
|
||||
string next_minidump_path_; |
||||
|
||||
// Pointers to the UTF-8 versions of above
|
||||
const char *dump_path_c_; |
||||
const char *next_minidump_id_c_; |
||||
const char *next_minidump_path_c_; |
||||
|
||||
// The callback function and pointer to be passed back after the minidump
|
||||
// has been written
|
||||
FilterCallback filter_; |
||||
MinidumpCallback callback_; |
||||
void *callback_context_; |
||||
|
||||
// The callback function to be passed back when we don't want a minidump
|
||||
// file to be written
|
||||
DirectCallback directCallback_; |
||||
|
||||
// The thread that is created for the handler
|
||||
pthread_t handler_thread_; |
||||
|
||||
// The port that is waiting on an exception message to be sent, if the
|
||||
// handler is installed
|
||||
mach_port_t handler_port_; |
||||
|
||||
// These variables save the previous exception handler's data so that it
|
||||
// can be re-installed when this handler is uninstalled
|
||||
ExceptionParameters *previous_; |
||||
|
||||
// True, if we've installed the exception handler
|
||||
bool installed_exception_handler_; |
||||
|
||||
// True, if we're in the process of uninstalling the exception handler and
|
||||
// the thread.
|
||||
bool is_in_teardown_; |
||||
|
||||
// Save the last result of the last minidump
|
||||
bool last_minidump_write_result_; |
||||
|
||||
// A mutex for use when writing out a minidump that was requested on a
|
||||
// thread other than the exception handler.
|
||||
pthread_mutex_t minidump_write_mutex_; |
||||
|
||||
// True, if we're using the mutext to indicate when mindump writing occurs
|
||||
bool use_minidump_write_mutex_; |
||||
}; |
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // CLIENT_MAC_HANDLER_EXCEPTION_HANDLER_H__
|
@ -0,0 +1,107 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
/*
|
||||
g++ -framework CoreFoundation -I../../.. \
|
||||
../../minidump_file_writer.cc \
|
||||
../../../common/convert_UTF.c \
|
||||
../../../common/string_conversion.cc \
|
||||
../../../common/mac/string_utilities.cc \
|
||||
exception_handler.cc \
|
||||
minidump_generator.cc \
|
||||
exception_handler_test.cc \
|
||||
-o exception_handler_test |
||||
*/ |
||||
|
||||
#include <pthread.h> |
||||
#include <pwd.h> |
||||
#include <unistd.h> |
||||
|
||||
#include <CoreFoundation/CoreFoundation.h> |
||||
|
||||
#include "exception_handler.h" |
||||
#include "minidump_generator.h" |
||||
|
||||
using std::string; |
||||
using google_breakpad::ExceptionHandler; |
||||
|
||||
static void *SleepyFunction(void *) { |
||||
while (1) { |
||||
sleep(10000); |
||||
} |
||||
} |
||||
|
||||
static void Crasher() { |
||||
int *a = NULL; |
||||
|
||||
fprintf(stdout, "Going to crash...\n"); |
||||
fprintf(stdout, "A = %d", *a); |
||||
} |
||||
|
||||
static void SoonToCrash() { |
||||
Crasher(); |
||||
} |
||||
|
||||
bool MDCallback(const char *dump_dir, const char *file_name, |
||||
void *context, bool success) { |
||||
string path(dump_dir); |
||||
string dest(dump_dir); |
||||
path.append(file_name); |
||||
path.append(".dmp"); |
||||
|
||||
fprintf(stdout, "Minidump: %s\n", path.c_str()); |
||||
// Indicate that we've handled the callback
|
||||
return true; |
||||
} |
||||
|
||||
int main(int argc, char * const argv[]) { |
||||
char buffer[PATH_MAX]; |
||||
struct passwd *user = getpwuid(getuid()); |
||||
|
||||
// Home dir
|
||||
snprintf(buffer, sizeof(buffer), "/Users/%s/Desktop/", user->pw_name); |
||||
|
||||
string path(buffer); |
||||
ExceptionHandler eh(path, NULL, MDCallback, NULL, true); |
||||
pthread_t t; |
||||
|
||||
if (pthread_create(&t, NULL, SleepyFunction, NULL) == 0) { |
||||
pthread_detach(t); |
||||
} else { |
||||
perror("pthread_create"); |
||||
} |
||||
|
||||
// Dump a test
|
||||
eh.WriteMinidump(); |
||||
|
||||
// Test the handler
|
||||
SoonToCrash(); |
||||
|
||||
return 0; |
||||
} |
@ -0,0 +1,989 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <cstdio> |
||||
|
||||
#include <mach/host_info.h> |
||||
#include <mach/mach_vm.h> |
||||
#include <mach/vm_statistics.h> |
||||
#include <mach-o/dyld.h> |
||||
#include <mach-o/loader.h> |
||||
#include <sys/sysctl.h> |
||||
#include <sys/resource.h> |
||||
#include <mach/mach_vm.h> |
||||
|
||||
#include <CoreFoundation/CoreFoundation.h> |
||||
|
||||
#include "client/mac/handler/minidump_generator.h" |
||||
#include "client/minidump_file_writer-inl.h" |
||||
#include "common/mac/file_id.h" |
||||
#include "common/mac/string_utilities.h" |
||||
|
||||
using MacStringUtils::ConvertToString; |
||||
using MacStringUtils::IntegerValueAtIndex; |
||||
|
||||
namespace google_breakpad { |
||||
|
||||
// constructor when generating from within the crashed process
|
||||
MinidumpGenerator::MinidumpGenerator() |
||||
: exception_type_(0), |
||||
exception_code_(0), |
||||
exception_thread_(0), |
||||
crashing_task_(mach_task_self()), |
||||
handler_thread_(mach_thread_self()), |
||||
dynamic_images_(NULL) { |
||||
GatherSystemInformation(); |
||||
} |
||||
|
||||
// constructor when generating from a different process than the
|
||||
// crashed process
|
||||
MinidumpGenerator::MinidumpGenerator(mach_port_t crashing_task, |
||||
mach_port_t handler_thread) |
||||
: exception_type_(0), |
||||
exception_code_(0), |
||||
exception_thread_(0), |
||||
crashing_task_(crashing_task), |
||||
handler_thread_(handler_thread) { |
||||
if (crashing_task != mach_task_self()) { |
||||
dynamic_images_ = new DynamicImages(crashing_task_); |
||||
} else { |
||||
dynamic_images_ = NULL; |
||||
} |
||||
|
||||
GatherSystemInformation(); |
||||
} |
||||
|
||||
MinidumpGenerator::~MinidumpGenerator() { |
||||
delete dynamic_images_; |
||||
} |
||||
|
||||
char MinidumpGenerator::build_string_[16]; |
||||
int MinidumpGenerator::os_major_version_ = 0; |
||||
int MinidumpGenerator::os_minor_version_ = 0; |
||||
int MinidumpGenerator::os_build_number_ = 0; |
||||
|
||||
// static
|
||||
void MinidumpGenerator::GatherSystemInformation() { |
||||
// If this is non-zero, then we've already gathered the information
|
||||
if (os_major_version_) |
||||
return; |
||||
|
||||
// This code extracts the version and build information from the OS
|
||||
CFStringRef vers_path = |
||||
CFSTR("/System/Library/CoreServices/SystemVersion.plist"); |
||||
CFURLRef sys_vers = |
||||
CFURLCreateWithFileSystemPath(NULL, |
||||
vers_path, |
||||
kCFURLPOSIXPathStyle, |
||||
false); |
||||
CFDataRef data; |
||||
SInt32 error; |
||||
CFURLCreateDataAndPropertiesFromResource(NULL, sys_vers, &data, NULL, NULL, |
||||
&error); |
||||
|
||||
if (!data) |
||||
return; |
||||
|
||||
CFDictionaryRef list = static_cast<CFDictionaryRef> |
||||
(CFPropertyListCreateFromXMLData(NULL, data, kCFPropertyListImmutable, |
||||
NULL)); |
||||
if (!list) |
||||
return; |
||||
|
||||
CFStringRef build_version = static_cast<CFStringRef> |
||||
(CFDictionaryGetValue(list, CFSTR("ProductBuildVersion"))); |
||||
CFStringRef product_version = static_cast<CFStringRef> |
||||
(CFDictionaryGetValue(list, CFSTR("ProductVersion"))); |
||||
string build_str = ConvertToString(build_version); |
||||
string product_str = ConvertToString(product_version); |
||||
|
||||
CFRelease(list); |
||||
CFRelease(sys_vers); |
||||
CFRelease(data); |
||||
|
||||
strlcpy(build_string_, build_str.c_str(), sizeof(build_string_)); |
||||
|
||||
// Parse the string that looks like "10.4.8"
|
||||
os_major_version_ = IntegerValueAtIndex(product_str, 0); |
||||
os_minor_version_ = IntegerValueAtIndex(product_str, 1); |
||||
os_build_number_ = IntegerValueAtIndex(product_str, 2); |
||||
} |
||||
|
||||
string MinidumpGenerator::UniqueNameInDirectory(const string &dir, |
||||
string *unique_name) { |
||||
CFUUIDRef uuid = CFUUIDCreate(NULL); |
||||
CFStringRef uuid_cfstr = CFUUIDCreateString(NULL, uuid); |
||||
CFRelease(uuid); |
||||
string file_name(ConvertToString(uuid_cfstr)); |
||||
CFRelease(uuid_cfstr); |
||||
string path(dir); |
||||
|
||||
// Ensure that the directory (if non-empty) has a trailing slash so that
|
||||
// we can append the file name and have a valid pathname.
|
||||
if (!dir.empty()) { |
||||
if (dir.at(dir.size() - 1) != '/') |
||||
path.append(1, '/'); |
||||
} |
||||
|
||||
path.append(file_name); |
||||
path.append(".dmp"); |
||||
|
||||
if (unique_name) |
||||
*unique_name = file_name; |
||||
|
||||
return path; |
||||
} |
||||
|
||||
bool MinidumpGenerator::Write(const char *path) { |
||||
WriteStreamFN writers[] = { |
||||
&MinidumpGenerator::WriteThreadListStream, |
||||
&MinidumpGenerator::WriteSystemInfoStream, |
||||
&MinidumpGenerator::WriteModuleListStream, |
||||
&MinidumpGenerator::WriteMiscInfoStream, |
||||
&MinidumpGenerator::WriteBreakpadInfoStream, |
||||
// Exception stream needs to be the last entry in this array as it may
|
||||
// be omitted in the case where the minidump is written without an
|
||||
// exception.
|
||||
&MinidumpGenerator::WriteExceptionStream, |
||||
}; |
||||
bool result = true; |
||||
|
||||
// If opening was successful, create the header, directory, and call each
|
||||
// writer. The destructor for the TypedMDRVAs will cause the data to be
|
||||
// flushed. The destructor for the MinidumpFileWriter will close the file.
|
||||
if (writer_.Open(path)) { |
||||
TypedMDRVA<MDRawHeader> header(&writer_); |
||||
TypedMDRVA<MDRawDirectory> dir(&writer_); |
||||
|
||||
if (!header.Allocate()) |
||||
return false; |
||||
|
||||
int writer_count = sizeof(writers) / sizeof(writers[0]); |
||||
|
||||
// If we don't have exception information, don't write out the
|
||||
// exception stream
|
||||
if (!exception_thread_ && !exception_type_) |
||||
--writer_count; |
||||
|
||||
// Add space for all writers
|
||||
if (!dir.AllocateArray(writer_count)) |
||||
return false; |
||||
|
||||
MDRawHeader *header_ptr = header.get(); |
||||
header_ptr->signature = MD_HEADER_SIGNATURE; |
||||
header_ptr->version = MD_HEADER_VERSION; |
||||
time(reinterpret_cast<time_t *>(&(header_ptr->time_date_stamp))); |
||||
header_ptr->stream_count = writer_count; |
||||
header_ptr->stream_directory_rva = dir.position(); |
||||
|
||||
MDRawDirectory local_dir; |
||||
for (int i = 0; (result) && (i < writer_count); ++i) { |
||||
result = (this->*writers[i])(&local_dir); |
||||
|
||||
if (result) |
||||
dir.CopyIndex(i, &local_dir); |
||||
} |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
size_t MinidumpGenerator::CalculateStackSize(mach_vm_address_t start_addr) { |
||||
mach_vm_address_t stack_region_base = start_addr; |
||||
mach_vm_size_t stack_region_size; |
||||
natural_t nesting_level = 0; |
||||
vm_region_submap_info_64 submap_info; |
||||
mach_msg_type_number_t info_count = VM_REGION_SUBMAP_INFO_COUNT_64; |
||||
|
||||
vm_region_recurse_info_t region_info; |
||||
region_info = reinterpret_cast<vm_region_recurse_info_t>(&submap_info); |
||||
|
||||
if (start_addr == 0) { |
||||
return 0; |
||||
} |
||||
|
||||
kern_return_t result = |
||||
mach_vm_region_recurse(crashing_task_, &stack_region_base, |
||||
&stack_region_size, &nesting_level, |
||||
region_info, |
||||
&info_count); |
||||
|
||||
if (start_addr < stack_region_base) { |
||||
// probably stack corruption, since mach_vm_region had to go
|
||||
// higher in the process address space to find a valid region.
|
||||
return 0; |
||||
} |
||||
|
||||
|
||||
if ((stack_region_base + stack_region_size) == TOP_OF_THREAD0_STACK) { |
||||
// The stack for thread 0 needs to extend all the way to
|
||||
// 0xc0000000 on 32 bit and 00007fff5fc00000 on 64bit. HOWEVER,
|
||||
// for many processes, the stack is first created in one page
|
||||
// below this, and is then later extended to a much larger size by
|
||||
// creating a new VM region immediately below the initial page.
|
||||
|
||||
// You can see this for yourself by running vmmap on a "hello,
|
||||
// world" program
|
||||
|
||||
// Because of the above, we'll add 4k to include the original
|
||||
// stack frame page.
|
||||
// This method of finding the stack region needs to be done in
|
||||
// a better way; the breakpad issue 247 is tracking this.
|
||||
stack_region_size += 0x1000; |
||||
} |
||||
|
||||
return result == KERN_SUCCESS ? |
||||
stack_region_base + stack_region_size - start_addr : 0; |
||||
} |
||||
|
||||
bool MinidumpGenerator::WriteStackFromStartAddress( |
||||
mach_vm_address_t start_addr, |
||||
MDMemoryDescriptor *stack_location) { |
||||
UntypedMDRVA memory(&writer_); |
||||
|
||||
bool result = false; |
||||
size_t size = CalculateStackSize(start_addr); |
||||
|
||||
if (size == 0) { |
||||
// In some situations the stack address for the thread can come back 0.
|
||||
// In these cases we skip over the threads in question and stuff the
|
||||
// stack with a clearly borked value.
|
||||
start_addr = 0xDEADBEEF; |
||||
size = 16; |
||||
if (!memory.Allocate(size)) |
||||
return false; |
||||
|
||||
unsigned long long dummy_stack[2]; // Fill dummy stack with 16 bytes of
|
||||
// junk.
|
||||
dummy_stack[0] = 0xDEADBEEF; |
||||
dummy_stack[1] = 0xDEADBEEF; |
||||
|
||||
result = memory.Copy(dummy_stack, size); |
||||
} else { |
||||
|
||||
if (!memory.Allocate(size)) |
||||
return false; |
||||
|
||||
if (dynamic_images_) { |
||||
|
||||
kern_return_t kr; |
||||
|
||||
void *stack_memory = ReadTaskMemory(crashing_task_, |
||||
(void*)start_addr, |
||||
size, |
||||
&kr); |
||||
|
||||
if (stack_memory == NULL) { |
||||
return false; |
||||
} |
||||
|
||||
result = memory.Copy(stack_memory, size); |
||||
free(stack_memory); |
||||
} else { |
||||
result = memory.Copy(reinterpret_cast<const void *>(start_addr), size); |
||||
} |
||||
} |
||||
|
||||
stack_location->start_of_memory_range = start_addr; |
||||
stack_location->memory = memory.location(); |
||||
|
||||
return result; |
||||
} |
||||
|
||||
#if TARGET_CPU_PPC || TARGET_CPU_PPC64 |
||||
bool MinidumpGenerator::WriteStack(breakpad_thread_state_data_t state, |
||||
MDMemoryDescriptor *stack_location) { |
||||
breakpad_thread_state_t *machine_state = |
||||
reinterpret_cast<breakpad_thread_state_t *>(state); |
||||
#if TARGET_CPU_PPC |
||||
mach_vm_address_t start_addr = machine_state->r1; |
||||
#else |
||||
mach_vm_address_t start_addr = machine_state->__r1; |
||||
#endif |
||||
return WriteStackFromStartAddress(start_addr, stack_location); |
||||
} |
||||
|
||||
u_int64_t |
||||
MinidumpGenerator::CurrentPCForStack(breakpad_thread_state_data_t state) { |
||||
breakpad_thread_state_t *machine_state = |
||||
reinterpret_cast<breakpad_thread_state_t *>(state); |
||||
|
||||
#if TARGET_CPU_PPC |
||||
return machine_state->srr0; |
||||
#else |
||||
return machine_state->__srr0; |
||||
#endif |
||||
} |
||||
|
||||
bool MinidumpGenerator::WriteContext(breakpad_thread_state_data_t state, |
||||
MDLocationDescriptor *register_location) { |
||||
TypedMDRVA<MinidumpContext> context(&writer_); |
||||
breakpad_thread_state_t *machine_state = |
||||
reinterpret_cast<breakpad_thread_state_t *>(state); |
||||
|
||||
if (!context.Allocate()) |
||||
return false; |
||||
|
||||
*register_location = context.location(); |
||||
MinidumpContext *context_ptr = context.get(); |
||||
context_ptr->context_flags = MD_CONTEXT_PPC_BASE; |
||||
|
||||
#if TARGET_CPU_PPC64 |
||||
#define AddReg(a) context_ptr->a = machine_state->__ ## a |
||||
#define AddGPR(a) context_ptr->gpr[a] = machine_state->__r ## a |
||||
#else |
||||
#define AddReg(a) context_ptr->a = machine_state->a |
||||
#define AddGPR(a) context_ptr->gpr[a] = machine_state->r ## a |
||||
#endif |
||||
|
||||
AddReg(srr0); |
||||
AddReg(cr); |
||||
AddReg(xer); |
||||
AddReg(ctr); |
||||
AddReg(lr); |
||||
AddReg(vrsave); |
||||
|
||||
AddGPR(0); |
||||
AddGPR(1); |
||||
AddGPR(2); |
||||
AddGPR(3); |
||||
AddGPR(4); |
||||
AddGPR(5); |
||||
AddGPR(6); |
||||
AddGPR(7); |
||||
AddGPR(8); |
||||
AddGPR(9); |
||||
AddGPR(10); |
||||
AddGPR(11); |
||||
AddGPR(12); |
||||
AddGPR(13); |
||||
AddGPR(14); |
||||
AddGPR(15); |
||||
AddGPR(16); |
||||
AddGPR(17); |
||||
AddGPR(18); |
||||
AddGPR(19); |
||||
AddGPR(20); |
||||
AddGPR(21); |
||||
AddGPR(22); |
||||
AddGPR(23); |
||||
AddGPR(24); |
||||
AddGPR(25); |
||||
AddGPR(26); |
||||
AddGPR(27); |
||||
AddGPR(28); |
||||
AddGPR(29); |
||||
AddGPR(30); |
||||
AddGPR(31); |
||||
|
||||
#if TARGET_CPU_PPC |
||||
/* The mq register is only for PPC */ |
||||
AddReg(mq); |
||||
#endif |
||||
|
||||
|
||||
return true; |
||||
} |
||||
|
||||
#elif TARGET_CPU_X86 || TARGET_CPU_X86_64 |
||||
|
||||
bool MinidumpGenerator::WriteStack(breakpad_thread_state_data_t state, |
||||
MDMemoryDescriptor *stack_location) { |
||||
breakpad_thread_state_t *machine_state = |
||||
reinterpret_cast<breakpad_thread_state_t *>(state); |
||||
|
||||
#if TARGET_CPU_X86_64 |
||||
mach_vm_address_t start_addr = machine_state->__rsp; |
||||
#else |
||||
mach_vm_address_t start_addr = machine_state->esp; |
||||
#endif |
||||
return WriteStackFromStartAddress(start_addr, stack_location); |
||||
} |
||||
|
||||
u_int64_t |
||||
MinidumpGenerator::CurrentPCForStack(breakpad_thread_state_data_t state) { |
||||
breakpad_thread_state_t *machine_state = |
||||
reinterpret_cast<breakpad_thread_state_t *>(state); |
||||
|
||||
#if TARGET_CPU_X86_64 |
||||
return machine_state->__rip; |
||||
#else |
||||
return machine_state->eip; |
||||
#endif |
||||
} |
||||
|
||||
bool MinidumpGenerator::WriteContext(breakpad_thread_state_data_t state, |
||||
MDLocationDescriptor *register_location) { |
||||
TypedMDRVA<MinidumpContext> context(&writer_); |
||||
breakpad_thread_state_t *machine_state = |
||||
reinterpret_cast<breakpad_thread_state_t *>(state); |
||||
|
||||
if (!context.Allocate()) |
||||
return false; |
||||
|
||||
*register_location = context.location(); |
||||
MinidumpContext *context_ptr = context.get(); |
||||
|
||||
#if TARGET_CPU_X86 |
||||
context_ptr->context_flags = MD_CONTEXT_X86; |
||||
|
||||
#define AddReg(a) context_ptr->a = machine_state->a |
||||
AddReg(eax); |
||||
AddReg(ebx); |
||||
AddReg(ecx); |
||||
AddReg(edx); |
||||
AddReg(esi); |
||||
AddReg(edi); |
||||
AddReg(ebp); |
||||
AddReg(esp); |
||||
|
||||
AddReg(cs); |
||||
AddReg(ds); |
||||
AddReg(ss); |
||||
AddReg(es); |
||||
AddReg(fs); |
||||
AddReg(gs); |
||||
AddReg(eflags); |
||||
|
||||
AddReg(eip); |
||||
#else |
||||
|
||||
#define AddReg(a) context_ptr->a = machine_state->__ ## a |
||||
context_ptr->context_flags = MD_CONTEXT_AMD64; |
||||
AddReg(rax); |
||||
AddReg(rbx); |
||||
AddReg(rcx); |
||||
AddReg(rdx); |
||||
AddReg(rdi); |
||||
AddReg(rsi); |
||||
AddReg(rbp); |
||||
AddReg(rsp); |
||||
AddReg(r8); |
||||
AddReg(r9); |
||||
AddReg(r10); |
||||
AddReg(r11); |
||||
AddReg(r12); |
||||
AddReg(r13); |
||||
AddReg(r14); |
||||
AddReg(r15); |
||||
AddReg(rip); |
||||
// according to AMD's software developer guide, bits above 18 are
|
||||
// not used in the flags register. Since the minidump format
|
||||
// specifies 32 bits for the flags register, we can truncate safely
|
||||
// with no loss.
|
||||
context_ptr->eflags = machine_state->__rflags; |
||||
AddReg(cs); |
||||
AddReg(fs); |
||||
AddReg(gs); |
||||
#endif |
||||
|
||||
return true; |
||||
} |
||||
#endif |
||||
|
||||
bool MinidumpGenerator::WriteThreadStream(mach_port_t thread_id, |
||||
MDRawThread *thread) { |
||||
breakpad_thread_state_data_t state; |
||||
mach_msg_type_number_t state_count = sizeof(state); |
||||
|
||||
if (thread_get_state(thread_id, BREAKPAD_MACHINE_THREAD_STATE, |
||||
state, &state_count) == |
||||
KERN_SUCCESS) { |
||||
if (!WriteStack(state, &thread->stack)) |
||||
return false; |
||||
|
||||
if (!WriteContext(state, &thread->thread_context)) |
||||
return false; |
||||
|
||||
thread->thread_id = thread_id; |
||||
} else { |
||||
return false; |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
bool MinidumpGenerator::WriteThreadListStream( |
||||
MDRawDirectory *thread_list_stream) { |
||||
TypedMDRVA<MDRawThreadList> list(&writer_); |
||||
thread_act_port_array_t threads_for_task; |
||||
mach_msg_type_number_t thread_count; |
||||
int non_generator_thread_count; |
||||
|
||||
if (task_threads(crashing_task_, &threads_for_task, &thread_count)) |
||||
return false; |
||||
|
||||
// Don't include the generator thread
|
||||
non_generator_thread_count = thread_count - 1; |
||||
if (!list.AllocateObjectAndArray(non_generator_thread_count, |
||||
sizeof(MDRawThread))) |
||||
return false; |
||||
|
||||
thread_list_stream->stream_type = MD_THREAD_LIST_STREAM; |
||||
thread_list_stream->location = list.location(); |
||||
|
||||
list.get()->number_of_threads = non_generator_thread_count; |
||||
|
||||
MDRawThread thread; |
||||
int thread_idx = 0; |
||||
|
||||
for (unsigned int i = 0; i < thread_count; ++i) { |
||||
memset(&thread, 0, sizeof(MDRawThread)); |
||||
|
||||
if (threads_for_task[i] != handler_thread_) { |
||||
if (!WriteThreadStream(threads_for_task[i], &thread)) |
||||
return false; |
||||
|
||||
list.CopyIndexAfterObject(thread_idx++, &thread, sizeof(MDRawThread)); |
||||
} |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
bool |
||||
MinidumpGenerator::WriteExceptionStream(MDRawDirectory *exception_stream) { |
||||
TypedMDRVA<MDRawExceptionStream> exception(&writer_); |
||||
|
||||
if (!exception.Allocate()) |
||||
return false; |
||||
|
||||
exception_stream->stream_type = MD_EXCEPTION_STREAM; |
||||
exception_stream->location = exception.location(); |
||||
MDRawExceptionStream *exception_ptr = exception.get(); |
||||
exception_ptr->thread_id = exception_thread_; |
||||
|
||||
// This naming is confusing, but it is the proper translation from
|
||||
// mach naming to minidump naming.
|
||||
exception_ptr->exception_record.exception_code = exception_type_; |
||||
exception_ptr->exception_record.exception_flags = exception_code_; |
||||
|
||||
breakpad_thread_state_data_t state; |
||||
mach_msg_type_number_t stateCount = sizeof(state); |
||||
|
||||
if (thread_get_state(exception_thread_, |
||||
BREAKPAD_MACHINE_THREAD_STATE, |
||||
state, |
||||
&stateCount) != KERN_SUCCESS) |
||||
return false; |
||||
|
||||
if (!WriteContext(state, &exception_ptr->thread_context)) |
||||
return false; |
||||
|
||||
exception_ptr->exception_record.exception_address = CurrentPCForStack(state); |
||||
|
||||
return true; |
||||
} |
||||
|
||||
bool MinidumpGenerator::WriteSystemInfoStream( |
||||
MDRawDirectory *system_info_stream) { |
||||
TypedMDRVA<MDRawSystemInfo> info(&writer_); |
||||
|
||||
if (!info.Allocate()) |
||||
return false; |
||||
|
||||
system_info_stream->stream_type = MD_SYSTEM_INFO_STREAM; |
||||
system_info_stream->location = info.location(); |
||||
|
||||
// CPU Information
|
||||
uint32_t cpu_type; |
||||
size_t len = sizeof(cpu_type); |
||||
sysctlbyname("hw.cputype", &cpu_type, &len, NULL, 0); |
||||
uint32_t number_of_processors; |
||||
len = sizeof(number_of_processors); |
||||
sysctlbyname("hw.ncpu", &number_of_processors, &len, NULL, 0); |
||||
MDRawSystemInfo *info_ptr = info.get(); |
||||
|
||||
switch (cpu_type) { |
||||
case CPU_TYPE_POWERPC: |
||||
info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_PPC; |
||||
break; |
||||
case CPU_TYPE_I386: |
||||
info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_X86; |
||||
#ifdef __i386__ |
||||
// ebx is used for PIC code, so we need
|
||||
// to preserve it.
|
||||
#define cpuid(op,eax,ebx,ecx,edx) \ |
||||
asm ("pushl %%ebx \n\t" \
|
||||
"cpuid \n\t" \
|
||||
"movl %%ebx,%1 \n\t" \
|
||||
"popl %%ebx" \
|
||||
: "=a" (eax), \
|
||||
"=g" (ebx), \
|
||||
"=c" (ecx), \
|
||||
"=d" (edx) \
|
||||
: "0" (op)) |
||||
int unused, unused2; |
||||
// get vendor id
|
||||
cpuid(0, unused, info_ptr->cpu.x86_cpu_info.vendor_id[0], |
||||
info_ptr->cpu.x86_cpu_info.vendor_id[2], |
||||
info_ptr->cpu.x86_cpu_info.vendor_id[1]); |
||||
// get version and feature info
|
||||
cpuid(1, info_ptr->cpu.x86_cpu_info.version_information, unused, unused2, |
||||
info_ptr->cpu.x86_cpu_info.feature_information); |
||||
// family
|
||||
info_ptr->processor_level = |
||||
(info_ptr->cpu.x86_cpu_info.version_information & 0xF00) >> 8; |
||||
// 0xMMSS (Model, Stepping)
|
||||
info_ptr->processor_revision = |
||||
(info_ptr->cpu.x86_cpu_info.version_information & 0xF) | |
||||
((info_ptr->cpu.x86_cpu_info.version_information & 0xF0) << 4); |
||||
#endif // __i386__
|
||||
break; |
||||
default: |
||||
info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_UNKNOWN; |
||||
break; |
||||
} |
||||
|
||||
info_ptr->number_of_processors = number_of_processors; |
||||
info_ptr->platform_id = MD_OS_MAC_OS_X; |
||||
|
||||
MDLocationDescriptor build_string_loc; |
||||
|
||||
if (!writer_.WriteString(build_string_, 0, |
||||
&build_string_loc)) |
||||
return false; |
||||
|
||||
info_ptr->csd_version_rva = build_string_loc.rva; |
||||
info_ptr->major_version = os_major_version_; |
||||
info_ptr->minor_version = os_minor_version_; |
||||
info_ptr->build_number = os_build_number_; |
||||
|
||||
return true; |
||||
} |
||||
|
||||
void setVersion(MDRawModule *module, uint32_t version, bool isMainExecutable) |
||||
{ |
||||
module->version_info.signature = MD_VSFIXEDFILEINFO_SIGNATURE; |
||||
module->version_info.struct_version |= MD_VSFIXEDFILEINFO_VERSION; |
||||
if (!isMainExecutable) { |
||||
// Convert MAC dylib version format, which is a 32 bit number, to the
|
||||
// format used by minidump. The mac format is <16 bits>.<8 bits>.<8 bits>
|
||||
// so it fits nicely into the windows version with some massaging
|
||||
// The mapping is:
|
||||
// 1) upper 16 bits of MAC version go to lower 16 bits of product HI
|
||||
// 2) Next most significant 8 bits go to upper 16 bits of product LO
|
||||
// 3) Least significant 8 bits go to lower 16 bits of product LO
|
||||
module->version_info.file_version_hi = 0; |
||||
module->version_info.file_version_hi = version >> 16; |
||||
module->version_info.file_version_lo = (version & 0xff00) << 8; |
||||
module->version_info.file_version_lo |= (version & 0xff); |
||||
} else { |
||||
// Convert the __TEXT __version section of the main executable
|
||||
module->version_info.file_version_hi = (version & 0xff000000) >> 8; |
||||
module->version_info.file_version_hi |= (version & 0x00ff0000) >> 16; |
||||
module->version_info.file_version_lo = (version & 0x0000ff00) << 8; |
||||
module->version_info.file_version_lo |= (version & 0x000000ff); |
||||
} |
||||
} |
||||
|
||||
bool MinidumpGenerator::WriteModuleStream(unsigned int index, |
||||
MDRawModule *module) { |
||||
if (dynamic_images_) { |
||||
// we're in a different process than the crashed process
|
||||
DynamicImage *image = dynamic_images_->GetImage(index); |
||||
|
||||
if (!image) |
||||
return false; |
||||
|
||||
const breakpad_mach_header *header = image->GetMachHeader(); |
||||
|
||||
if (!header) |
||||
return false; |
||||
|
||||
int cpu_type = header->cputype; |
||||
|
||||
memset(module, 0, sizeof(MDRawModule)); |
||||
|
||||
MDLocationDescriptor string_location; |
||||
|
||||
const char* name = image->GetFilePath(); |
||||
if (!writer_.WriteString(name, 0, &string_location)) |
||||
return false; |
||||
|
||||
module->base_of_image = image->GetVMAddr() + image->GetVMAddrSlide(); |
||||
module->size_of_image = image->GetVMSize(); |
||||
module->module_name_rva = string_location.rva; |
||||
|
||||
setVersion(module, image->GetVersion(), index == (uint32_t)FindExecutableModule()); |
||||
|
||||
if (!WriteCVRecord(module, cpu_type, name)) { |
||||
return false; |
||||
} |
||||
} else { |
||||
// we're getting module info in the crashed process
|
||||
|
||||
const breakpad_mach_header *header; |
||||
header = (breakpad_mach_header*)_dyld_get_image_header(index); |
||||
if (!header) |
||||
return false; |
||||
|
||||
#ifdef __LP64__ |
||||
assert(header->magic == MH_MAGIC_64); |
||||
|
||||
if(header->magic != MH_MAGIC_64) |
||||
return false; |
||||
#else |
||||
assert(header->magic == MH_MAGIC); |
||||
|
||||
if(header->magic != MH_MAGIC) |
||||
return false; |
||||
#endif |
||||
|
||||
int cpu_type = header->cputype; |
||||
unsigned long slide = _dyld_get_image_vmaddr_slide(index); |
||||
const char* name = _dyld_get_image_name(index); |
||||
const struct load_command *cmd = |
||||
reinterpret_cast<const struct load_command *>(header + 1); |
||||
|
||||
memset(module, 0, sizeof(MDRawModule)); |
||||
|
||||
for (unsigned int i = 0; cmd && (i < header->ncmds); i++) { |
||||
if (cmd->cmd == LC_SEGMENT) { |
||||
|
||||
const breakpad_mach_segment_command *seg = |
||||
reinterpret_cast<const breakpad_mach_segment_command *>(cmd); |
||||
|
||||
if (!strcmp(seg->segname, "__TEXT")) { |
||||
MDLocationDescriptor string_location; |
||||
|
||||
if (!writer_.WriteString(name, 0, &string_location)) |
||||
return false; |
||||
|
||||
module->base_of_image = seg->vmaddr + slide; |
||||
module->size_of_image = seg->vmsize; |
||||
module->module_name_rva = string_location.rva; |
||||
|
||||
// The header MUST NOT be copied, but as it is free'd by the DynamicImage destructor, we have to leak the DynamicImage
|
||||
// The other option is to rewrite the content of DynamicImage::CalculateMemoryAndVersionInfo() to get the version
|
||||
DynamicImage *image = new DynamicImage((breakpad_mach_header*)header, 0, NULL, (char*)name, 0, MACH_PORT_NULL); |
||||
setVersion(module, image->GetVersion(), index == (uint32_t)FindExecutableModule()); |
||||
|
||||
if (!WriteCVRecord(module, cpu_type, name)) |
||||
return false; |
||||
|
||||
return true; |
||||
} |
||||
} |
||||
|
||||
cmd = reinterpret_cast<struct load_command*>((char *)cmd + cmd->cmdsize); |
||||
} |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
int MinidumpGenerator::FindExecutableModule() { |
||||
if (dynamic_images_) { |
||||
int index = dynamic_images_->GetExecutableImageIndex(); |
||||
|
||||
if (index >= 0) { |
||||
return index; |
||||
} |
||||
} else { |
||||
int image_count = _dyld_image_count(); |
||||
const struct mach_header *header; |
||||
|
||||
for (int index = 0; index < image_count; ++index) { |
||||
header = _dyld_get_image_header(index); |
||||
|
||||
if (header->filetype == MH_EXECUTE) |
||||
return index; |
||||
} |
||||
} |
||||
|
||||
// failed - just use the first image
|
||||
return 0; |
||||
} |
||||
|
||||
bool MinidumpGenerator::WriteCVRecord(MDRawModule *module, int cpu_type, |
||||
const char *module_path) { |
||||
TypedMDRVA<MDCVInfoPDB70> cv(&writer_); |
||||
|
||||
// Only return the last path component of the full module path
|
||||
const char *module_name = strrchr(module_path, '/'); |
||||
|
||||
// Increment past the slash
|
||||
if (module_name) |
||||
++module_name; |
||||
else |
||||
module_name = "<Unknown>"; |
||||
|
||||
size_t module_name_length = strlen(module_name); |
||||
|
||||
if (!cv.AllocateObjectAndArray(module_name_length + 1, sizeof(u_int8_t))) |
||||
return false; |
||||
|
||||
if (!cv.CopyIndexAfterObject(0, module_name, module_name_length)) |
||||
return false; |
||||
|
||||
module->cv_record = cv.location(); |
||||
MDCVInfoPDB70 *cv_ptr = cv.get(); |
||||
cv_ptr->cv_signature = MD_CVINFOPDB70_SIGNATURE; |
||||
cv_ptr->age = 0; |
||||
|
||||
// Get the module identifier
|
||||
FileID file_id(module_path); |
||||
unsigned char identifier[16]; |
||||
|
||||
if (file_id.MachoIdentifier(cpu_type, identifier)) { |
||||
cv_ptr->signature.data1 = (uint32_t)identifier[0] << 24 | |
||||
(uint32_t)identifier[1] << 16 | (uint32_t)identifier[2] << 8 | |
||||
(uint32_t)identifier[3]; |
||||
cv_ptr->signature.data2 = (uint32_t)identifier[4] << 8 | identifier[5]; |
||||
cv_ptr->signature.data3 = (uint32_t)identifier[6] << 8 | identifier[7]; |
||||
cv_ptr->signature.data4[0] = identifier[8]; |
||||
cv_ptr->signature.data4[1] = identifier[9]; |
||||
cv_ptr->signature.data4[2] = identifier[10]; |
||||
cv_ptr->signature.data4[3] = identifier[11]; |
||||
cv_ptr->signature.data4[4] = identifier[12]; |
||||
cv_ptr->signature.data4[5] = identifier[13]; |
||||
cv_ptr->signature.data4[6] = identifier[14]; |
||||
cv_ptr->signature.data4[7] = identifier[15]; |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
bool MinidumpGenerator::WriteModuleListStream( |
||||
MDRawDirectory *module_list_stream) { |
||||
TypedMDRVA<MDRawModuleList> list(&writer_); |
||||
|
||||
int image_count = dynamic_images_ ? |
||||
dynamic_images_->GetImageCount() : _dyld_image_count(); |
||||
|
||||
if (!list.AllocateObjectAndArray(image_count, MD_MODULE_SIZE)) |
||||
return false; |
||||
|
||||
module_list_stream->stream_type = MD_MODULE_LIST_STREAM; |
||||
module_list_stream->location = list.location(); |
||||
list.get()->number_of_modules = image_count; |
||||
|
||||
// Write out the executable module as the first one
|
||||
MDRawModule module; |
||||
int executableIndex = FindExecutableModule(); |
||||
|
||||
if (!WriteModuleStream(executableIndex, &module)) { |
||||
return false; |
||||
} |
||||
|
||||
list.CopyIndexAfterObject(0, &module, MD_MODULE_SIZE); |
||||
int destinationIndex = 1; // Write all other modules after this one
|
||||
|
||||
for (int i = 0; i < image_count; ++i) { |
||||
if (i != executableIndex) { |
||||
if (!WriteModuleStream(i, &module)) { |
||||
return false; |
||||
} |
||||
|
||||
list.CopyIndexAfterObject(destinationIndex++, &module, MD_MODULE_SIZE); |
||||
} |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
bool MinidumpGenerator::WriteMiscInfoStream(MDRawDirectory *misc_info_stream) { |
||||
TypedMDRVA<MDRawMiscInfo> info(&writer_); |
||||
|
||||
if (!info.Allocate()) |
||||
return false; |
||||
|
||||
misc_info_stream->stream_type = MD_MISC_INFO_STREAM; |
||||
misc_info_stream->location = info.location(); |
||||
|
||||
MDRawMiscInfo *info_ptr = info.get(); |
||||
info_ptr->size_of_info = sizeof(MDRawMiscInfo); |
||||
info_ptr->flags1 = MD_MISCINFO_FLAGS1_PROCESS_ID | |
||||
MD_MISCINFO_FLAGS1_PROCESS_TIMES | |
||||
MD_MISCINFO_FLAGS1_PROCESSOR_POWER_INFO; |
||||
|
||||
// Process ID
|
||||
info_ptr->process_id = getpid(); |
||||
|
||||
// Times
|
||||
struct rusage usage; |
||||
if (getrusage(RUSAGE_SELF, &usage) != -1) { |
||||
// Omit the fractional time since the MDRawMiscInfo only wants seconds
|
||||
info_ptr->process_user_time = usage.ru_utime.tv_sec; |
||||
info_ptr->process_kernel_time = usage.ru_stime.tv_sec; |
||||
} |
||||
int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, info_ptr->process_id }; |
||||
size_t size; |
||||
if (!sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &size, NULL, 0)) { |
||||
mach_vm_address_t addr; |
||||
if (mach_vm_allocate(mach_task_self(), |
||||
&addr, |
||||
size, |
||||
true) == KERN_SUCCESS) { |
||||
struct kinfo_proc *proc = (struct kinfo_proc *)addr; |
||||
if (!sysctl(mib, sizeof(mib) / sizeof(mib[0]), proc, &size, NULL, 0)) |
||||
info_ptr->process_create_time = proc->kp_proc.p_starttime.tv_sec; |
||||
mach_vm_deallocate(mach_task_self(), addr, size); |
||||
} |
||||
} |
||||
|
||||
// Speed
|
||||
uint64_t speed; |
||||
size = sizeof(speed); |
||||
sysctlbyname("hw.cpufrequency_max", &speed, &size, NULL, 0); |
||||
info_ptr->processor_max_mhz = speed / (1000 * 1000); |
||||
info_ptr->processor_mhz_limit = speed / (1000 * 1000); |
||||
size = sizeof(speed); |
||||
sysctlbyname("hw.cpufrequency", &speed, &size, NULL, 0); |
||||
info_ptr->processor_current_mhz = speed / (1000 * 1000); |
||||
|
||||
return true; |
||||
} |
||||
|
||||
bool MinidumpGenerator::WriteBreakpadInfoStream( |
||||
MDRawDirectory *breakpad_info_stream) { |
||||
TypedMDRVA<MDRawBreakpadInfo> info(&writer_); |
||||
|
||||
if (!info.Allocate()) |
||||
return false; |
||||
|
||||
breakpad_info_stream->stream_type = MD_BREAKPAD_INFO_STREAM; |
||||
breakpad_info_stream->location = info.location(); |
||||
MDRawBreakpadInfo *info_ptr = info.get(); |
||||
|
||||
if (exception_thread_ && exception_type_) { |
||||
info_ptr->validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID | |
||||
MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID; |
||||
info_ptr->dump_thread_id = handler_thread_; |
||||
info_ptr->requesting_thread_id = exception_thread_; |
||||
} else { |
||||
info_ptr->validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID; |
||||
info_ptr->dump_thread_id = handler_thread_; |
||||
info_ptr->requesting_thread_id = 0; |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
} // namespace google_breakpad
|
@ -0,0 +1,157 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// minidump_generator.h: Create a minidump of the current MacOS process.
|
||||
|
||||
#ifndef CLIENT_MAC_GENERATOR_MINIDUMP_GENERATOR_H__ |
||||
#define CLIENT_MAC_GENERATOR_MINIDUMP_GENERATOR_H__ |
||||
|
||||
#include <mach/mach.h> |
||||
|
||||
#include <string> |
||||
|
||||
#include "client/minidump_file_writer.h" |
||||
#include "google_breakpad/common/minidump_format.h" |
||||
#include "common/mac/macho_utilities.h" |
||||
|
||||
#include "dynamic_images.h" |
||||
|
||||
namespace google_breakpad { |
||||
|
||||
using std::string; |
||||
|
||||
#if TARGET_CPU_X86_64 || TARGET_CPU_PPC64 |
||||
#define TOP_OF_THREAD0_STACK 0x00007fff5fbff000 |
||||
#else |
||||
#define TOP_OF_THREAD0_STACK 0xbffff000 |
||||
#endif |
||||
|
||||
#if TARGET_CPU_X86_64 |
||||
typedef x86_thread_state64_t breakpad_thread_state_t; |
||||
typedef MDRawContextAMD64 MinidumpContext; |
||||
#elif TARGET_CPU_X86 |
||||
typedef i386_thread_state_t breakpad_thread_state_t; |
||||
typedef MDRawContextX86 MinidumpContext; |
||||
#elif TARGET_CPU_PPC64 |
||||
typedef ppc_thread_state64_t breakpad_thread_state_t; |
||||
typedef MDRawContextPPC64 MinidumpContext; |
||||
#elif TARGET_CPU_PPC |
||||
typedef ppc_thread_state_t breakpad_thread_state_t; |
||||
typedef MDRawContextPPC MinidumpContext; |
||||
#endif |
||||
|
||||
// Creates a minidump file of the current process. If there is exception data,
|
||||
// use SetExceptionInformation() to add this to the minidump. The minidump
|
||||
// file is generated by the Write() function.
|
||||
// Usage:
|
||||
// MinidumpGenerator minidump();
|
||||
// minidump.Write("/tmp/minidump");
|
||||
//
|
||||
class MinidumpGenerator { |
||||
public: |
||||
MinidumpGenerator(); |
||||
MinidumpGenerator(mach_port_t crashing_task, mach_port_t handler_thread); |
||||
|
||||
~MinidumpGenerator(); |
||||
|
||||
// Return <dir>/<unique_name>.dmp
|
||||
// Sets |unique_name| (if requested) to the unique name for the minidump
|
||||
static string UniqueNameInDirectory(const string &dir, string *unique_name); |
||||
|
||||
// Write out the minidump into |path|
|
||||
// All of the components of |path| must exist and be writable
|
||||
// Return true if successful, false otherwise
|
||||
bool Write(const char *path); |
||||
|
||||
// Specify some exception information, if applicable
|
||||
void SetExceptionInformation(int type, int code, mach_port_t thread_name) { |
||||
exception_type_ = type; |
||||
exception_code_ = code; |
||||
exception_thread_ = thread_name; |
||||
} |
||||
|
||||
// Gather system information. This should be call at least once before using
|
||||
// the MinidumpGenerator class.
|
||||
static void GatherSystemInformation(); |
||||
|
||||
private: |
||||
typedef bool (MinidumpGenerator::*WriteStreamFN)(MDRawDirectory *); |
||||
|
||||
// Stream writers
|
||||
bool WriteThreadListStream(MDRawDirectory *thread_list_stream); |
||||
bool WriteExceptionStream(MDRawDirectory *exception_stream); |
||||
bool WriteSystemInfoStream(MDRawDirectory *system_info_stream); |
||||
bool WriteModuleListStream(MDRawDirectory *module_list_stream); |
||||
bool WriteMiscInfoStream(MDRawDirectory *misc_info_stream); |
||||
bool WriteBreakpadInfoStream(MDRawDirectory *breakpad_info_stream); |
||||
|
||||
// Helpers
|
||||
u_int64_t CurrentPCForStack(breakpad_thread_state_data_t state); |
||||
bool WriteStackFromStartAddress(mach_vm_address_t start_addr, |
||||
MDMemoryDescriptor *stack_location); |
||||
bool WriteStack(breakpad_thread_state_data_t state, |
||||
MDMemoryDescriptor *stack_location); |
||||
bool WriteContext(breakpad_thread_state_data_t state, |
||||
MDLocationDescriptor *register_location); |
||||
bool WriteThreadStream(mach_port_t thread_id, MDRawThread *thread); |
||||
bool WriteCVRecord(MDRawModule *module, int cpu_type,
|
||||
const char *module_path); |
||||
bool WriteModuleStream(unsigned int index, MDRawModule *module); |
||||
|
||||
size_t CalculateStackSize(mach_vm_address_t start_addr); |
||||
|
||||
int FindExecutableModule(); |
||||
|
||||
// disallow copy ctor and operator=
|
||||
explicit MinidumpGenerator(const MinidumpGenerator &); |
||||
void operator=(const MinidumpGenerator &); |
||||
|
||||
// Use this writer to put the data to disk
|
||||
MinidumpFileWriter writer_; |
||||
|
||||
// Exception information
|
||||
int exception_type_; |
||||
int exception_code_; |
||||
mach_port_t exception_thread_; |
||||
mach_port_t crashing_task_; |
||||
mach_port_t handler_thread_; |
||||
|
||||
// System information
|
||||
static char build_string_[16]; |
||||
static int os_major_version_; |
||||
static int os_minor_version_; |
||||
static int os_build_number_; |
||||
|
||||
// Information about dynamically loaded code
|
||||
DynamicImages *dynamic_images_; |
||||
}; |
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // CLIENT_MAC_GENERATOR_MINIDUMP_GENERATOR_H__
|
@ -0,0 +1,82 @@ |
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <unistd.h> |
||||
|
||||
#include <pthread.h> |
||||
#include <pwd.h> |
||||
|
||||
#include <CoreFoundation/CoreFoundation.h> |
||||
|
||||
#include "minidump_generator.h" |
||||
#include "minidump_file_writer.h" |
||||
|
||||
using std::string; |
||||
using google_breakpad::MinidumpGenerator; |
||||
|
||||
static bool doneWritingReport = false; |
||||
|
||||
static void *Reporter(void *) { |
||||
char buffer[PATH_MAX]; |
||||
MinidumpGenerator md; |
||||
struct passwd *user = getpwuid(getuid()); |
||||
|
||||
// Write it to the desktop
|
||||
snprintf(buffer, |
||||
sizeof(buffer), |
||||
"/Users/%s/Desktop/test.dmp", |
||||
user->pw_name); |
||||
|
||||
fprintf(stdout, "Writing %s\n", buffer); |
||||
unlink(buffer); |
||||
md.Write(buffer); |
||||
doneWritingReport = true; |
||||
|
||||
return NULL; |
||||
} |
||||
|
||||
static void SleepyFunction() { |
||||
while (!doneWritingReport) { |
||||
usleep(100); |
||||
} |
||||
} |
||||
|
||||
int main(int argc, char * const argv[]) { |
||||
pthread_t reporter_thread; |
||||
|
||||
if (pthread_create(&reporter_thread, NULL, Reporter, NULL) == 0) { |
||||
pthread_detach(reporter_thread); |
||||
} else { |
||||
perror("pthread_create"); |
||||
} |
||||
|
||||
SleepyFunction(); |
||||
|
||||
return 0; |
||||
} |
@ -0,0 +1,20 @@ |
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> |
||||
<plist version="1.0"> |
||||
<dict> |
||||
<key>CFBundleDevelopmentRegion</key> |
||||
<string>English</string> |
||||
<key>CFBundleExecutable</key> |
||||
<string>${EXECUTABLE_NAME}</string> |
||||
<key>CFBundleIdentifier</key> |
||||
<string>com.google.breakpad.minidump_tests32</string> |
||||
<key>CFBundleInfoDictionaryVersion</key> |
||||
<string>6.0</string> |
||||
<key>CFBundlePackageType</key> |
||||
<string>BNDL</string> |
||||
<key>CFBundleSignature</key> |
||||
<string>????</string> |
||||
<key>CFBundleVersion</key> |
||||
<string>1.0</string> |
||||
</dict> |
||||
</plist> |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue