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