restore old code

preferencesAboutTextFull
Claudio Valerio 14 years ago
parent d5ebe9cc98
commit 83cee687bd
  1. BIN
      thirdparty/google-breakpad/r318/bin/macx/dump_syms
  2. BIN
      thirdparty/google-breakpad/r318/bin/win32/dump_syms.exe
  3. 315
      thirdparty/google-breakpad/r318/breakpad.pro
  4. 258
      thirdparty/google-breakpad/r318/include/google_breakpad/client/mac/handler/breakpad_exc_server.h
  5. 43
      thirdparty/google-breakpad/r318/include/google_breakpad/client/mac/handler/breakpad_nlist_64.h
  6. 297
      thirdparty/google-breakpad/r318/include/google_breakpad/client/mac/handler/dynamic_images.h
  7. 212
      thirdparty/google-breakpad/r318/include/google_breakpad/client/mac/handler/exception_handler.h
  8. 157
      thirdparty/google-breakpad/r318/include/google_breakpad/client/mac/handler/minidump_generator.h
  9. 85
      thirdparty/google-breakpad/r318/include/google_breakpad/client/mac/handler/protected_memory_allocator.h
  10. 94
      thirdparty/google-breakpad/r318/include/google_breakpad/client/minidump_file_writer-inl.h
  11. 250
      thirdparty/google-breakpad/r318/include/google_breakpad/client/minidump_file_writer.h
  12. 63
      thirdparty/google-breakpad/r318/include/google_breakpad/client/windows/common/auto_critical_section.h
  13. 179
      thirdparty/google-breakpad/r318/include/google_breakpad/client/windows/common/ipc_protocol.h
  14. 170
      thirdparty/google-breakpad/r318/include/google_breakpad/client/windows/crash_generation/client_info.h
  15. 159
      thirdparty/google-breakpad/r318/include/google_breakpad/client/windows/crash_generation/crash_generation_client.h
  16. 269
      thirdparty/google-breakpad/r318/include/google_breakpad/client/windows/crash_generation/crash_generation_server.h
  17. 121
      thirdparty/google-breakpad/r318/include/google_breakpad/client/windows/crash_generation/minidump_generator.h
  18. 415
      thirdparty/google-breakpad/r318/include/google_breakpad/client/windows/handler/exception_handler.h
  19. 125
      thirdparty/google-breakpad/r318/include/google_breakpad/client/windows/sender/crash_report_sender.h
  20. 143
      thirdparty/google-breakpad/r318/include/google_breakpad/common/convert_UTF.h
  21. 31
      thirdparty/google-breakpad/r318/include/google_breakpad/common/md5.h
  22. 66
      thirdparty/google-breakpad/r318/include/google_breakpad/common/string_conversion.h
  23. 58
      thirdparty/google-breakpad/r318/include/google_breakpad/common/windows/guid_string.h
  24. 125
      thirdparty/google-breakpad/r318/include/google_breakpad/common/windows/http_upload.h
  25. 163
      thirdparty/google-breakpad/r318/include/google_breakpad/common/windows/pdb_source_line_writer.h
  26. 139
      thirdparty/google-breakpad/r318/include/google_breakpad/common/windows/string_utils-inl.h
  27. 83
      thirdparty/google-breakpad/r318/include/google_breakpad/google_breakpad/common/breakpad_types.h
  28. 231
      thirdparty/google-breakpad/r318/include/google_breakpad/google_breakpad/common/minidump_cpu_amd64.h
  29. 163
      thirdparty/google-breakpad/r318/include/google_breakpad/google_breakpad/common/minidump_cpu_ppc.h
  30. 129
      thirdparty/google-breakpad/r318/include/google_breakpad/google_breakpad/common/minidump_cpu_ppc64.h
  31. 158
      thirdparty/google-breakpad/r318/include/google_breakpad/google_breakpad/common/minidump_cpu_sparc.h
  32. 172
      thirdparty/google-breakpad/r318/include/google_breakpad/google_breakpad/common/minidump_cpu_x86.h
  33. 85
      thirdparty/google-breakpad/r318/include/google_breakpad/google_breakpad/common/minidump_exception_linux.h
  34. 193
      thirdparty/google-breakpad/r318/include/google_breakpad/google_breakpad/common/minidump_exception_mac.h
  35. 94
      thirdparty/google-breakpad/r318/include/google_breakpad/google_breakpad/common/minidump_exception_solaris.h
  36. 102
      thirdparty/google-breakpad/r318/include/google_breakpad/google_breakpad/common/minidump_exception_win32.h
  37. 721
      thirdparty/google-breakpad/r318/include/google_breakpad/google_breakpad/common/minidump_format.h
  38. 107
      thirdparty/google-breakpad/r318/include/google_breakpad/google_breakpad/common/minidump_size.h
  39. 114
      thirdparty/google-breakpad/r318/include/google_breakpad/google_breakpad/processor/basic_source_line_resolver.h
  40. 77
      thirdparty/google-breakpad/r318/include/google_breakpad/google_breakpad/processor/call_stack.h
  41. 94
      thirdparty/google-breakpad/r318/include/google_breakpad/google_breakpad/processor/code_module.h
  42. 98
      thirdparty/google-breakpad/r318/include/google_breakpad/google_breakpad/processor/code_modules.h
  43. 76
      thirdparty/google-breakpad/r318/include/google_breakpad/google_breakpad/processor/memory_region.h
  44. 904
      thirdparty/google-breakpad/r318/include/google_breakpad/google_breakpad/processor/minidump.h
  45. 94
      thirdparty/google-breakpad/r318/include/google_breakpad/google_breakpad/processor/minidump_processor.h
  46. 115
      thirdparty/google-breakpad/r318/include/google_breakpad/google_breakpad/processor/process_state.h
  47. 82
      thirdparty/google-breakpad/r318/include/google_breakpad/google_breakpad/processor/source_line_resolver_interface.h
  48. 84
      thirdparty/google-breakpad/r318/include/google_breakpad/google_breakpad/processor/stack_frame.h
  49. 153
      thirdparty/google-breakpad/r318/include/google_breakpad/google_breakpad/processor/stack_frame_cpu.h
  50. 140
      thirdparty/google-breakpad/r318/include/google_breakpad/google_breakpad/processor/stackwalker.h
  51. 82
      thirdparty/google-breakpad/r318/include/google_breakpad/google_breakpad/processor/symbol_supplier.h
  52. 97
      thirdparty/google-breakpad/r318/include/google_breakpad/google_breakpad/processor/system_info.h
  53. 92
      thirdparty/google-breakpad/r318/include/google_breakpad/processor/address_map-inl.h
  54. 80
      thirdparty/google-breakpad/r318/include/google_breakpad/processor/address_map.h
  55. 95
      thirdparty/google-breakpad/r318/include/google_breakpad/processor/basic_code_module.h
  56. 85
      thirdparty/google-breakpad/r318/include/google_breakpad/processor/basic_code_modules.h
  57. 197
      thirdparty/google-breakpad/r318/include/google_breakpad/processor/contained_range_map-inl.h
  58. 145
      thirdparty/google-breakpad/r318/include/google_breakpad/processor/contained_range_map.h
  59. 193
      thirdparty/google-breakpad/r318/include/google_breakpad/processor/linked_ptr.h
  60. 153
      thirdparty/google-breakpad/r318/include/google_breakpad/processor/logging.h
  61. 53
      thirdparty/google-breakpad/r318/include/google_breakpad/processor/pathname_stripper.h
  62. 282
      thirdparty/google-breakpad/r318/include/google_breakpad/processor/postfix_evaluator-inl.h
  63. 158
      thirdparty/google-breakpad/r318/include/google_breakpad/processor/postfix_evaluator.h
  64. 210
      thirdparty/google-breakpad/r318/include/google_breakpad/processor/range_map-inl.h
  65. 126
      thirdparty/google-breakpad/r318/include/google_breakpad/processor/range_map.h
  66. 335
      thirdparty/google-breakpad/r318/include/google_breakpad/processor/scoped_ptr.h
  67. 125
      thirdparty/google-breakpad/r318/include/google_breakpad/processor/simple_symbol_supplier.h
  68. 126
      thirdparty/google-breakpad/r318/include/google_breakpad/processor/stack_frame_info.h
  69. 80
      thirdparty/google-breakpad/r318/include/google_breakpad/processor/stackwalker_amd64.h
  70. 81
      thirdparty/google-breakpad/r318/include/google_breakpad/processor/stackwalker_ppc.h
  71. 86
      thirdparty/google-breakpad/r318/include/google_breakpad/processor/stackwalker_sparc.h
  72. 82
      thirdparty/google-breakpad/r318/include/google_breakpad/processor/stackwalker_x86.h
  73. BIN
      thirdparty/google-breakpad/r318/lib/macx/libbreakpad.a
  74. BIN
      thirdparty/google-breakpad/r318/lib/win32/breakpad.lib
  75. BIN
      thirdparty/google-breakpad/r318/lib/win32/dbreakpad.lib
  76. 9
      thirdparty/google-breakpad/r318/readme.txt
  77. 17
      thirdparty/google-breakpad/r318/release.vc9.bat
  78. 55
      thirdparty/google-breakpad/r318/src/client/linux/handler/Makefile
  79. 304
      thirdparty/google-breakpad/r318/src/client/linux/handler/exception_handler.cc
  80. 226
      thirdparty/google-breakpad/r318/src/client/linux/handler/exception_handler.h
  81. 124
      thirdparty/google-breakpad/r318/src/client/linux/handler/exception_handler_test.cc
  82. 411
      thirdparty/google-breakpad/r318/src/client/linux/handler/linux_thread.cc
  83. 204
      thirdparty/google-breakpad/r318/src/client/linux/handler/linux_thread.h
  84. 224
      thirdparty/google-breakpad/r318/src/client/linux/handler/linux_thread_test.cc
  85. 815
      thirdparty/google-breakpad/r318/src/client/linux/handler/minidump_generator.cc
  86. 73
      thirdparty/google-breakpad/r318/src/client/linux/handler/minidump_generator.h
  87. 86
      thirdparty/google-breakpad/r318/src/client/linux/handler/minidump_test.cc
  88. 1750
      thirdparty/google-breakpad/r318/src/client/mac/handler/breakpad_exc_server.c
  89. 258
      thirdparty/google-breakpad/r318/src/client/mac/handler/breakpad_exc_server.h
  90. 381
      thirdparty/google-breakpad/r318/src/client/mac/handler/breakpad_nlist_64.cc
  91. 43
      thirdparty/google-breakpad/r318/src/client/mac/handler/breakpad_nlist_64.h
  92. 456
      thirdparty/google-breakpad/r318/src/client/mac/handler/dynamic_images.cc
  93. 297
      thirdparty/google-breakpad/r318/src/client/mac/handler/dynamic_images.h
  94. 722
      thirdparty/google-breakpad/r318/src/client/mac/handler/exception_handler.cc
  95. 212
      thirdparty/google-breakpad/r318/src/client/mac/handler/exception_handler.h
  96. 107
      thirdparty/google-breakpad/r318/src/client/mac/handler/exception_handler_test.cc
  97. 989
      thirdparty/google-breakpad/r318/src/client/mac/handler/minidump_generator.cc
  98. 157
      thirdparty/google-breakpad/r318/src/client/mac/handler/minidump_generator.h
  99. 82
      thirdparty/google-breakpad/r318/src/client/mac/handler/minidump_generator_test.cc
  100. 20
      thirdparty/google-breakpad/r318/src/client/mac/handler/minidump_tests32-Info.plist
  101. Some files were not shown because too many files have changed in this diff Show More

@ -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> &parameters,
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> &parameters,
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> &parameters,
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> &parameters);
// 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__

@ -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(&regs, 0, sizeof(regs));
if (threads->GetRegisters(thread_info.pid, &regs)) {
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, &regs)) {
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(&regs, 0, sizeof(regs));
if (!thread_lister->GetRegisters(thread_info.pid, &regs)) {
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(), &regs, &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;
}

@ -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,
&region_base,
&region_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,
&region_base2,
&region_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,
&current.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…
Cancel
Save